簡體   English   中英

如何找出當前IP和BP寄存器的完整調用堆棧?

[英]How can I figure out the full call stack with the current IP and BP registers?

我正在使用GCC 5.4對Ubuntu LTS 16.04.1 X86_64進行簡單的實驗。

實驗是獲取正在運行的C程序的完整調用堆棧。

我所做的是:

  • 使用ptrace的PTRACE_ATTACH和PTRACE_GETREGS暫停正在運行的C程序並獲取其當前的IP和BP。
  • 使用PTRACE_PEEKDATA獲取[BP]和[BP + 4]的數據(或64位目標的+8),這樣我就可以得到調用函數的BP和返回地址。

因為BP是一個鏈,我應該能夠得到一系列的返回地址。 之后,通過使用列表文件或矮人數據分析地址序列,我終於能夠計算出完整的調用堆棧。 像'main - > funcA - > funcB - > funcC ...'之類的東西。

我的問題是,如果調用堆棧完全在我的測試程序的代碼中,這可以正常工作。 我的意思是每個函數都是由我編寫的。 但是,如果測試程序在CRT或系統API中停止,例如'scanf'或'sleep',則BP鏈不再起作用。

我檢查了disassambly並注意到CRT或系統API函數沒有通過'push ebp'和'mov ebp,esp'建立堆棧幀,就像我的函數一樣。 難怪為什么上述方法不起作用。 但我無法解釋為什么GDB在這種情況下仍能正常工作?! 因此,對於Linux C程序的調用堆棧,必須有許多我不知道的事情。

你能算出我的錯誤/誤會嗎? 或者你可以簡單地建議我閱讀一些文章/鏈接? 非常感謝你。

因為BP是一個鏈條

他們不是 過去曾經是在i386使用了一個幀指針鏈,但是幾年后,即使在i386上,GCC也默認使用-fomit-frame-pointer進行優化編譯。 x86_64-fno-omit-frame-pointer 從未成為優化代碼中的默認值。

如果調用堆棧完全在我的測試程序代碼中,這可以正常工作。

只有在沒有優化的情況下進行編譯時才有效(或者如果你使用-fno-omit-frame-pointer )。

我無法解釋為什么GDB在這種情況下仍能正常工作

GDB(和libunwind )使用DWARF展開信息,您可以使用readelf -wf a.out檢查它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM