2011-01-22 91 views
5

我知道我可以使用backtrace()或[NSThread callStackSymbols]獲取當前線程的堆棧跟蹤,但是如何獲取不同線程的堆棧跟蹤(假設它已被凍結)?從另一個線程打印堆棧跟蹤

回答

10

編輯:我原來的答案不會從任意線程打印。我寫的,因爲適當的執行在我崩潰處理項目:https://github.com/kstenerud/KSCrash

具體而言,這些文件:

與一些幫助:

你要做的就是:

  • 創建一個新的機器上下文結構(_STRUCT_MCONTEXT)
  • 使用thread_get_state在其堆棧狀態填寫()
  • 獲得程序計數器(第一個堆棧跟蹤條目)和幀指針(所有其餘部分)
  • 逐步通過幀指針指向的堆棧幀並存儲所有指令在緩衝區中放置以供以後使用。

請注意,您應該在執行此操作之前暫停該線程,否則您可能會得到不可預知的結果。

堆棧幀滿足包含兩個指針結構:

  • 指針到下一級的堆棧
  • 指令地址

所以,你需要考慮到這一點時,走框架填寫你的堆棧跟蹤。還有可能是堆棧損壞,導致指針不正確,從而導致程序崩潰。你可以通過使用vm_read_overwrite()來複制內存,它首先詢問內核是否有權訪問內存,所以它不會崩潰。一旦你有堆棧跟蹤,你可以像正常一樣調用backtrace()(crash handler必須是異步安全的,所以它實現了自己的回溯方法,但是在正常情況下,backtrace()很好) 。

+0

請注意,您應在讀取堆棧時暫停該線程。 – Albert 2012-04-06 18:42:51

3

下面是從另一個線程獲取callstack的更安全的方法:Implementationsome background information。它使用信號處理並在目標線程中產生一個信號處理程序。它的優點還在於它比您的解決方案更具跨平臺性,即它可以在您擁有<signal.h><execinfo.h>的任何地方工作。

對於印刷,您可以像您自己的建議一樣使用backtrace_symbols。但是你可能會對here的擴展版本感興趣。它使用libbfd(來自binutils;最近的版本也主要在MacOSX上工作,請參閱here,以瞭解可能與您無關的小限制)讀取調試信息並添加行號和其他信息(它也回退到dladdr如果一切都失敗了;那就是backtrace_symbols正在做什麼)。