如何在 Ubuntu 除錯第三方函式庫
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 libjpeg
或 apt-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》有稍微相關的基本教學,留著備忘。