2014-04-04 59 views
3

我有一個傳統GDB命令腳本,用於根據Python 2.6源代碼附帶的GDB腳本獲取Python堆棧跟蹤(SO不允許超鏈接,但這裏是網址:http://#%20http://svn.python.org/view/*checkout*/python/branches/release26-maint/Misc/傳統GDB腳本中堆棧跟蹤的停止條件

該腳本有一個while循環,基於退出的程序計數器有一個相當脆弱的檢查,這可能僅適用於直接運行Python的情況(如註釋中的原始代碼所述)如果解釋器是從C/C++應用程序啓動的話,則不行。

現有while循環是這樣的:

while $pc < Py_Main || $pc > Py_GetArgcArgv 
    # ... 
    # code for extracting Python stack from local vars in relevant frames 
    # of C stack 
    # ... 

    up-silently 1 

因爲我要調試的程序,對Py_MainPy_GetArgcArgv支票都不會很好地工作,所以我在尋找一個循環條件當它達到main時,它將評估爲false。

所以我一直在玩弄使用程序計數器,幀指針和堆棧指針的想法,因爲如果up-silently失敗,它們將具有與先前相同的值,這意味着我在堆棧頂部,像這樣:

set $oldpc = -1 
set $oldfp = -1 
set $oldsp = -1 
while !($oldpc == $pc && $oldfp == $fp && $oldsp == $sp) 
    # ... 
    # code for extracting Python stack from local vars in relevant frames 
    # of C stack 
    # ... 

    set $oldpc = $pc 
    set $oldsp = $sp 
    set $oldfp = $fp 
    up-silently 1 

我認爲這應該做的伎倆,初步檢查表明它工作正常。不過,我並不太熟悉編譯器可以做的各種優化,我擔心可能存在某些角落的情況,他們可能有效地在堆棧中的某處處於相同位置。

看起來$fp對於幀指針已被優化掉的呼叫可以爲零(例如,通過使用GCC編譯使用-g -O3)。我也不確定$pc是否可以依賴於不同,特別是如果遞歸調用正在發生。我希望$sp會有所不同,雖然仍然有待處理的堆棧,但是我有一個模糊的懷疑,即與tail recursion相關的優化可能導致$ sp相同。

任何意見將不勝感激。

具體的問題:

問題1:是否有遺留(非Python)的GDB腳本更好的方式來弄清楚,如果你在堆棧的頂部?

問題2:將我的$sp$pc$fp假設持有多數或全部優化方案真的嗎?

回答

1

所以我沒有回答問題1,但我想我可以部分回答問題2

Tail recursion確實會重用現有的堆棧指針和幀指針。這意味着堆棧跟蹤的意思是多次調用相同優化的尾遞歸函數只會在一次出現,因爲(顯然)堆棧指針正在被重用(並且沒有新的堆棧或幀指針被推送)。

這似乎意味着您可以檢查$ sp的以前和當前值停止條件。不幸的是,$ sp值在堆棧中間可能是相同的。這似乎發生在某些函數調用已被優化掉的情況下。

因此,我在我的問題中提出的停止條件可能相當脆弱,即使它適用於幾個現實世界的例子。