我有一個非常大、非常古老、非常拜占庭式、非常無證的 Fortran 代碼集,我正在嘗試對其進行故障排除。由于部分大致如下所示,它在運行時給了我除零問題:
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
實際上/cblk/,我從運行中發現了 3 個帶有宣告的包含標頭grep -in "/cblk/" *.h *.f *.F:“commonincludes.h”、“commonincludes2.h”和“commonincludes3.h”。作為一個額外的好處,對應于r和的記憶體部分在“commonincludes.h”中z被命名x,y即“commonincludes'h”看起來像:
common /cblk/ x(12),y(12),otherstuff
r我的問題是,我不知道在哪里z設定。我曾經grep找到每個包含每個標題的地方,但我看不到任何寫入變數的地方。
如果我檢查gdb 中r和z發生錯誤的實際值,這些值看起來是合理的——它們是非零、看起來不是垃圾的實數向量,只是r(6)等于r(8)和z(6)等于z(8)導致了問題。
我需要找到z并r寫入,但我在 gdb 檔案中找不到任何關于將觀察點附加到COMMON塊的說明。我怎樣才能找到這些寫入的位置?
uj5u.com熱心網友回復:
我想我已經弄清楚了如何去做我想做的事情。因為COMMON變數是靜態分配的,所以它們的地址不應該隨著運行而改變。因此,當我的程式由于被零除錯誤而停止時,我能夠找到 (在此示例中) 的記憶體地址,該地址r(8)在范圍內是全域的,不應在后續運行中更改。然后,我可以使用該地址上的觀察點重新運行代碼,并且當代碼中的任何地方的值發生變化時,它都會標記。
在我的示例中,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)
$1 = (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
我通過運行回溯確認這確實是設定我的公共塊變數的地方(大概是第一個地方)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/474290.html
