gdb 如何找到 debug symbol

先前在《追踪 glibc 裡的程式》提到自己如何亂試, 試出讓 gdb 讀到 debug symbol。昨天聽 Scott 說明, 才知道背後是怎麼一回事。

在 Ubuntu 下以 libm 為例, 在 /lib/x86_64-linux-gnu/libm-2.13.so 裡面, 先看一些相關的 section header:

$ objdump -h /lib/x86_64-linux-gnu/libm-2.13.so | grep gnu
/lib/x86_64-linux-gnu/libm-2.13.so:     file format elf64-x86-64
  0 .note.gnu.build-id 00000024  0000000000000238  0000000000000238  00000238  2**2
  2 .gnu.hash     00000fa4  0000000000000280  0000000000000280  00000280  2**3
  5 .gnu.version  00000298  00000000000038da  00000000000038da  000038da  2**1
  6 .gnu.version_d 0000005c  0000000000003b78  0000000000003b78  00003b78  2**3
  7 .gnu.version_r 00000030  0000000000003bd8  0000000000003bd8  00003bd8  2**3
 27 .gnu_debuglink 00000014  0000000000000000  0000000000000000  000840e4  2**0

幾個重點

  • .note.gnu.build-id 表示 binary id, 之後用來比對 debug symbol 是否出自 shared lib。看起來 Fedora 在找 debug symbol 時, 有用到 binary id; 而 Ubuntu 沒有的樣子, 我用 hexedit 亂改這個 section 的值, 仍能找到 debug symbol
  • .gnu_debuglink 指向包含 debug symbol 的檔案, 若用 hexedit 改掉它的值, 執行 gdb /lib/x86_64-linux-gnu/libm-2.13.so, gdb 會表示找不到 libm 的 debug symbol
  • 可用 objdump -s -j .gnu_debuglink /lib/x86_64-linux-gnu/libm-2.13.so 顯示 section 內容

若用 LD_PRELOAD=/usr/lib/debug/lib/x86_64-linux-gnu/libm-2.13.so ANY_PROGRAM 執行程式, 結果會 segmentation fault, 所以我推測 Ubuntu 下 X-dbg 裡包的檔案, 可能和 Fedora 一樣, 只有 debug symbol 而不是完整 strip 前的函式庫。不知要如何確認該檔案裡只有 debug symbol 沒有實際的 object code。

至於確認原本的 binary (object file / shared lib / executable) 是否有編入 debug symbol, 除了用 objdump -S 再找看看有沒有出現程式碼外, 更簡單的作法是用 objdump -h | grep debug:

$ objdump -h /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.13.so | grep debug
/usr/lib/debug/lib/x86_64-linux-gnu/libm-2.13.so:     file format elf64-x86-64
 28 .debug_aranges 00004770  0000000000000000  0000000000000000  000002b0  2**4
 29 .debug_pubnames 00002e44  0000000000000000  0000000000000000  00004a20  2**0
 30 .debug_info   000318ee  0000000000000000  0000000000000000  00007864  2**0
 31 .debug_abbrev 00010fc3  0000000000000000  0000000000000000  00039152  2**0
 32 .debug_line   00018c20  0000000000000000  0000000000000000  0004a115  2**0
 33 .debug_str    000041bc  0000000000000000  0000000000000000  00062d35  2**0
 34 .debug_loc    00062bc5  0000000000000000  0000000000000000  00066ef1  2**0
 35 .debug_pubtypes 00003a11  0000000000000000  0000000000000000  000c9ab6  2**0
 36 .debug_ranges 00003e30  0000000000000000  0000000000000000  000cd4c7  2**0

有上述 section 的話, 表示有含 debug symbols。

備註

1. hexedit 基本指令

  • F1: 等同於 man hexedit
  • F4: 跳到 offset, 對照 objdump -h X 看倒數第二欄使用
  • TAB: 切換 hexadecimal 或 ascii 區, 之後取代內容或搜尋, 和這有關
  • 直接在 byte 上打字取代
  • /: 找字串
  • ctrl+c / ctrl+x: 離開 / 存檔離開

2. 見《The DWARF Debugging Standard》了解 debug 資訊如何存在檔案, 只是留著備忘, 目前應該沒必要去讀。

3. 若是自己編含 debug symbol 的函式庫, 就不是上述那一回事了, 而是直接編進目前的函式庫裡。

4. 《Separate Debug Files - Debugging with GDB》說明 gdb 如何支援分離 debug symbol 到另一個檔案, 另外 man strip 或 man objcopy, 可在 "--only-keep-debug" 的部份看到相關說明。看來要知道到底各個 distribution 怎麼做這事, 去看該 distribution 官方的說明會比較確實。之後再看看吧。

留言

這個網誌中的熱門文章

(C/C++ ) 如何在 Linux 上使用自行編譯的第三方函式庫

virtualbox 使用 USB 裝置

熟悉系統工具好處多多