2011年12月21日 星期三

列出用到的 shared library

本文整理大家的建議和自己實際操作的心得。新手上路, 有錯還請指正。

static library 就是一包 object file, 沒什麼需要提的, static library 沒有記錄其它資訊。所以, 編 shared library 或 executable 時要自行處理好 static library 的相依性, 在前篇有提到一點資訊。

shared library 有兩種, 一種在 linking 時要指定好 shared library 用到的 undefined symbol 放在那些 shared library 裡, 待執行時再載入到記憶體使用; 另一種用 dlopen() 和 dlsym() 載入 (這兩個函式存在 libdl 內)。

前者比較單純, 可用 ldd 透過靜態分析了解用到那些 shared library, 且各自實際指到的檔案。ldd 本身是一個 shell script, 用到 ld.so 事先定義的一些機制 (LD_TRACE_LOADED_OBJECTS) 來讀取資料, man ld.so 裡有相關的說明。其中 LD_LIBRARY_PATH 和 LD_PRELOAD 相當實用, 無法在連結時解決問題時, 至少還有這招可在載入時處理。

若想分析透過 dlopen() 載入的動態函式庫, 有幾個做法

  • 在程式執行中觀察 /proc/PID/maps, 這個檔案記錄 process 用到的各區段記憶體為何, 可從對應到的檔案看出有載入的 shared library。必要時可配合 gdb 在想觀察的部份停住, 再從外部看 /proc/PID/maps這裡man proc 有相關說明。
  • strace 執行程式, 觀察開啟的檔案: strace -f -e open PROGRAM 2>&1 | grep "\.so"

就我自己小試的心得, 看 /proc/PID/maps 最穩, 且方便看各別 process、thread 載入的函式庫, 也不會拖慢觀察目標的執行程式。不過 strace 不需配合 gdb 停在該停的地方, 就「快篩」的角度來看, 也滿有用的, 加上 -f 後方便追蹤 multi-process、multi-thread, 不過執行速度好像有慢一些, 不太確定。之後再比較看看兩者適合的使用時機。

參考資料

2011-12-22 更新

  • 依 wens 和 Scott 的留言更新上面 strace 的例子。
  • strace -e 的參數看來頗有用的, 之後有需求時再來研究。

7 則留言:

  1. Use: strace -e trace=open,mmap 省掉grep

    回覆刪除
  2. 這篇已經相當完整了! :)

    我最常用的就是 /proc/PID/maps 和類似 wens 上面留言中那樣用 strace. 你 strace 的用法有一點點鱉腳:
    1. 因為 mmap 需要 file descriptor 所以一定會先呼叫 open
    2. 故 strace -eopen -f PROGRAM | grep '\.so' 即可(除非有類似 Python 在 Windows 下將 .dll 改名成 .pyd 的奇怪命名規則)

    你看到的 ldd 是 glibc 的版本。
    glibc 內的動態連結器 (/lib64/ld-linux.so.2) 可用:
    LD_DEBUG=all MY-PROGRAM
    看 runtime 每個 symbol 怎麼找的。
    但 Anroid 、或用 uClibc 的 Linux 系統上不是用 glibc 所以不適用。
    ldd 會遞迴列出 dependency, i.e.: EXE -> libA -> libB 會連間接依賴的 libB 也列出,要分辨直接依賴的可用:
    eu-readelf -d MY-LIB | grep NEEDED

    在 Linux 下開發程式會用到的 package manager 指令我有張 RPM 與 DPKG 的對照表,寫在:
    http://itrs.tw/wiki/RPM_DPKG_Rosetta_Stone

    另一個好玩的基礎問題是:一個 .so,/proc/PID/maps 為何會出現多次?

    (嚴格說 Posix 中傳回 file descriptor 的函式除了 open 還有:
    http://udrepper.livejournal.com/20407.html
    但會用來 mmap 的 file descriptor 都是 open 傳回的)

    回覆刪除
  3. 真多資訊啊, 之後有用到時再來慢慢消化, 謝啦

    btw, 這張表真不錯, 每次重讀都會多學到一點指令, 之前什麼都 apt-file search, 不知道有 dpkg --search 可找已裝的套件
    http://itrs.tw/wiki/RPM_DPKG_Rosetta_Stone

    回覆刪除
  4. @Scott, /proc/PID/maps .so會出現多次是為甚饃阿, 難道他在memory當中不連續? 有分segment?

    回覆刪除
  5. @Yu-Teh Shen: 提示:權限不同,你要不要自己研究看看?
    你將
    $ cat /proc/PID/maps

    $ eu-readelf -a PROGRAM
    (找 Section Headers)
    對著看,猜的應該差不多。
    我們 1/8 見面可對對答案 :)

    回覆刪除
  6. @Scott: .so 也是ELF type, 所以也有.data, .bss, .text 這些section, 而這些section權限也不一樣 (.text .init r+x, .bss r+w), 但是load進來的時候他會按照permission來切割, 而不是直接照section分page, 這應該就是/proc/PID/maps 所對應到的.

    回覆刪除

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...