如何在 Ubuntu 除錯第三方函式庫

fcamel
fcamel的程式開發心得
5 min readAug 13, 2018

Ubuntu 上用 apt-get 安裝第三方函式庫。這篇說明使用這些函式庫遇到錯誤時,如何獲得進一步資訊協助除錯。

取得 debug symbol 和原始碼

若程式掛在第三方函式庫,需要 debug symbol 才能看到掛在那。

對於 Ubuntu 上的函式庫 X 來說:

  • X-dev 表示讓開發者用的,有裝 header、文件之類的。
  • X-dbg 帶有 X 的 debug symbol。

像 libjpeg8 就會有對應的 libjpeg8-dev 和 libjpeg8-dbg。裝好 X-dbg 後,gdb 會知道如何載入。可以用 aptitude search libjpegapt-cache search libjpeg 找相關套件。

再來用 apt-get source X取得原始碼。下指令前記得確定 /etc/apt/sources.list 內用deb-src …指定原始碼來源,然後執行 apt-get update 更新來源列表。

若希望在 gdb 裡看原始碼 (用 cgdb 的話會直接切半個視窗顯示),需要在 gdb 用 set substitute-path from to 設定路徑字串取代,或用 directory 指定原始碼位置,細節見《Debugging with GDB: 9.5 Specifying Source Directories》。舉例來說,若 gdb 要看的檔案是 ../a/b.c,就要用指令 directory SOURCE_PATH 指定 SOURCE_PATH,然後 SOURCE_PATH/../a/b.c 真的有你要看的 b.c。這裡有在 gdb 內看 bash 原始碼的例子。

找出包含函式庫的套件

有些函式庫的名稱和套件名稱不同,以 libm 為例,可以用 locate 找出 libm 的位置:

$ locate libm.so | egrep "^/(usr|lib)/"
/lib/i386-linux-gnu/libm.so.6
/lib/x86_64-linux-gnu/libm.so.6
/usr/arm-linux-gnueabi/lib/libm.so
/usr/arm-linux-gnueabi/lib/libm.so.6
/usr/arm-linux-gnueabihf/lib/libm.so
/usr/arm-linux-gnueabihf/lib/libm.so.6
/usr/lib/x86_64-linux-gnu/libm.so
/usr/lib32/libm.so
/usr/libx32/libm.so

然後用 apt-file 找出套件名稱:

$ apt-file search /usr/lib/x86_64-linux-gnu/libm.so
libc6-dev: /usr/lib/x86_64-linux-gnu/libm.so

或是用 dpkg --search 從檔名找套件:

$ dpkg --search libm.so
libc6-i386: /lib32/libm.so.6
libc6-dev-i386: /usr/lib32/libm.so
libc6:amd64: /lib/x86_64-linux-gnu/libm.so.6
libc6-dev-armel-cross: /usr/arm-linux-gnueabi/lib/libm.so
libc6-dev-x32: /usr/libx32/libm.so
libc6-dev-armhf-cross: /usr/arm-linux-gnueabihf/lib/libm.so
libc6-armhf-cross: /usr/arm-linux-gnueabihf/lib/libm.so.6
libc6-dev:amd64: /usr/lib/x86_64-linux-gnu/libm.so
libc6:i386: /lib/i386-linux-gnu/libm.so.6
libc6-armel-cross: /usr/arm-linux-gnueabi/lib/libm.so.6
libc6-x32: /libx32/libm.so.6

自行編譯 debug symbol

若官方沒提供 X-dbg,可以自己編一份。

參考官方文件《HowToGetABacktrace — Debian Wiki》,作法如下:

$ sudo apt-get install build-essential fakeroot gdb
$ sudo apt-get build-dep X
$ DEB_BUILD_OPTIONS=”nostrip noopt” fakeroot apt-get -b source X
$ sudo dpkg -i X.deb

暫時替換自己編譯的版本

若只是暫時除錯用或需要頻繁修改加 log 觀察更多訊息。改用 LD_PRELOAD 在執行時替換編好的 shared library 比較方便,不用打包成 debian package。

以在 Ubuntu 16.04 上使用 GTK+為例,作法如下:

$ sudo apt-get install build-essential
$ sudo apt-get build-dep libgtk-3-0:amd64
$ apt-get source libgtk-3-0:amd64
$ cd gtk+3.0-3.18.9/
$ ./configure
$ make
$ LD_PRELOAD=/path/to/gtk+3.0-3.18.9/gtk/.libs/libgtk-3.so MY_PROG

如此一來,可以隨時修改 gtk+3.0–3.18.9/ 下的程式,重編出 libgtk-3.so 再執行 MY_PROG,方便理解 GTK+ 的行為。

注意有些套件抓下原始碼後會編不過,這時需要 apt-get build-dep X 安裝相依的套件。

LD_PRELOAD 的相關的說明,可以參考《Linux 執行時尋找 symbol 的流程以及 shared library 相關知識》

相關資料

《CompilingEasyHowTo》《CompilingSoftware》有稍微相關的基本教學,留著備忘。

--

--