我可以将手表添加到 COMMON 块吗?

Can I add a watch to a COMMON block?

我有一组非常大、非常旧、非常复杂、非常没有文档记录的 Fortran 代码,我正在尝试对其进行故障排除。它在 运行 时给了我 divide-by-zero 问题,因为部分大致如下:

subroutine badsub(ainput)
      implicit double precision (a-h,o-z)
      include 'commonincludes2.h'
      x=dsqrt((r(6)-r(8))**2+(z(6)-z(8))**2)
      y=ainput
      w=y+x
      v=2./dlog(dsqrt(w/y))

此代码在最后一行命中除以零,因为 y 等于 w 因为 x 为零,因此 dlog(dsqrt(1) 为零。

包含文件看起来像这样:

common /cblk/ r(12),z(12),otherstuff

实际上有 3 个 include headers with /cblk/ 我从 运行ning grep -in "/cblk/" *.h *.f *.F 中找到的声明:“commonincludes.h”,“commonincludes2.h”和“commonincludes3.h”。作为额外的奖励,对应于 rz 的内存部分在“commonincludes.h”中被命名为 xy,即“commonincludes'h”看起来像:

common /cblk/ x(12),y(12),otherstuff

我的问题是,我不知道设置 rz 的位置。我已经使用 grep 找到每个包含 headers 的地方,但我没有看到任何写入变量的地方。

如果我在发生错误的 gdb 中检查 rz 中的实际值,这些值看起来很合理——它们是 non-zero、not-garbage-looking 向量的实数,只是 r(6) 等于 r(8)z(6) 等于 z(8) 导致问题。

我需要找到写入 zr 的位置,但我在 gdb 文档中找不到任何关于将观察点附加到 COMMON 块的说明。我怎样才能找到这些文件的写入位置?

我想我已经想出了如何做我想做的事情。因为 COMMON 变量是静态分配的,所以它们的地址不应该从 运行 运行 改变。因此,当我的程序由于我的 divide-by-zero 错误而停止时,我能够找到(在本例中)r(8) 的内存地址,它是全局范围的,不应在后续 运行s。然后,我可以 re-run 在该地址上带有观察点的代码,当代码中任何位置的值发生变化时,它都会进行标记。

在我的例子中,gdb 会话看起来像这样,进程名称和目录被归档以保护罪犯:

Reading symbols from myprogram...
(gdb) r
Starting program: ************

Program received signal SIGFPE, Arithmetic exception.
0x00000000004df96d in badsub (ainput=1875.0000521766287) at badsub.f:109
109               v=2./dlog(dsqrt(w/y))
(gdb) p &r(8)
 = (PTR TO -> ( real(kind=8) )) 0xcbf7618 <cblk_+56>
(gdb) watch *(double precision *) 0x0cbf7618
Hardware watchpoint 1: *(double precision *) 0x0cbf7618
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: *************

Hardware watchpoint 1: *(double precision *) 0x0cbf7618

Old value = 0
New value = 6.123233995736766e-17
0x00007ffff6f2be2d in __memmove_avx_unaligned_erms () from /lib64/libc.so.6

我已经从 运行 回溯中确认这确实是我的公共块变量被设置的地方(大概是第一个地方)。