Core-Dump

如何從 coredump 重建堆棧跟踪?

  • September 25, 2019

coredumpctl創建 coredump 後,該實用程序會顯示程序的堆棧跟踪。

例如,在 Firefox 核心轉儲上:

Stack trace of thread 14469:
#0  0x00007f0ac652d3bd pthread_cond_wait@@GLIBC_2.3.2 (libpthread.so.0)
#1  0x0000560f2ab95488 _ZN7mozilla6detail21ConditionVariableImpl4waitERNS0_9MutexImplE (firefox)
#2  0x0000560f2ab95646 _ZN7mozilla6detail21ConditionVariableImpl8wait_forERNS0_9MutexImplERKNS_16BaseTimeDurationINS_27TimeDurati>
#3  0x00007f0aba9799f9 n/a (libxul.so)
#4  0x00007f0aba96eb9a n/a (libxul.so)
#5  0x00007f0ac652708c start_thread (libpthread.so.0)
#6  0x00007f0ac5abce7f __clone (libc.so.6)

考慮到這是 C 程式碼,因此它是編譯的,符號並沒有直接嵌入到二進製文件中:那麼這怎麼可能呢?

而且,readelf 在實踐中是如何做到的?

(我的猜測,這與嵌入在 ELF 文件中的符號表有關)

正如您正確猜測的那樣,符號來自嵌入在 ELF 文件中的符號資訊。即使不存在完整的符號表,也需要一些符號資訊才能進行動態連結。

就實際的堆棧跟踪而言,當呼叫函式時,會保存 cpu 返回的位置。對於像 x86 這樣的 cpu,它被壓入堆棧。對於 RISC 機器,它通常被放入寄存器。如果函式想要呼叫任何其他函式(即它不是leaf函式)然後這個寄存器被壓入堆棧。堆棧跟踪程式碼在堆棧上找到這些地址,在其前面的符號中查找最近的地址並報告它。一些堆棧跟踪程式碼會同時列印符號名稱和距離,這可以讓您對它的準確性更有信心。例如,如果符號在返回地址之前只有 40 個字節,那麼與之前的 40,000 個字節相比,人們對它在該程式碼中的信心要大得多。在後一種情況下,人們可能會懷疑返回地址指向不同的函式,但該函式在符號表中沒有條目。

很多事情都會使這不准確。如果編譯器將函式 a 內聯到函式 b 中,那麼您可能在函式 a 中,但堆棧跟踪會報告您在 b 中。

如果編譯器執行“尾呼叫優化”,其中函式 a 以類似的結尾return b();並且函式 c 呼叫函式 a,您可能希望跟踪顯示 c->a->b,但您只會看到 c->b。如果您查看 c 的原始碼並且您發現它從不直接呼叫 b,這可能會令人困惑。

引用自:https://unix.stackexchange.com/questions/543731