記得 2006 年 chroot/Hacks in Taiwan Conference 的發起人 timshu 曾經出版過一書 《Linux C函式庫詳解辭典》,這本書含括了超過 400 個函式,成為許多 Linux 軟體開發者的參考手邊書。

雖然 Linux/Unix 系統上有相當多的參考文件,只要你知道該問什麼問題,都可以找到答案。但是線上手冊 (man pages, info)常缺乏系統式的整理,新手頗難入手。且 man pages 有時言簡意賅,缺乏範例程式,往往不容易閱讀。因此像是《Linux C函式庫詳解辭典》便極有參考價值。

類似的系統 API 書籍還有 Robert LoveLinux System Programming: Talking Directly to the Kernel and C Library。rlove 的書對於各系統層廣度足夠,可惜深度不足,書中充滿提示,你得有足夠的背景知識纔全然理解他所要傳達的資訊,而具體的實務應用資訊也不足,無法用來當作字典臨時查詢需要的 API 與範例。

2010 年十月,Michael Kerrisk 發表了 TLPI – The Linux Programming Interface,Michael Kerrisk 是 Linux man-pages Project 的維護者,文件維護者出書其份量與內容勢必可觀,TLPI 內容超過 1500 頁、超過 60 個章節、超過 200 個範例,內容除了含括 POSIX.1-2001/SUSv3POSIX.1-2008/SUSv4 外,也包含了許多 Linux 獨有的特色,對於跨 UNIX 作業系統移植性亦有著墨,相對於 Richard Stevens 與 Stephen A. Rago 的 Advanced Programming in the UNIX Environment ,圖表與內容均不遜色,且每個章節都至少有一題練習題。

值得一提的是,TLPI 除了介紹 system calls 外,文中也試著說明 2.4.x. 到 2.6.x (2.6.34) 間核心變動對於系統的影響。

推薦 Linux 軟體開發者備妥一本作為案頭書。

開源工具現狀

許多開發者都有介入中大型專案的經驗,常必須試圖理解原始程式的設計,或多或少都有在程式碼迷宮中找路的經驗。有些專案,程式碼結構嚴謹,軟體設計應用 Design Patterns. 見名稱、參數即可推斷程式結構,閱讀如沐春風。

但若碰到未經重構的成年老專案,程式邏輯因為年久失修,塞滿各個開發階段的臨時解決方案,常常已經複雜到難以一眼望穿理解。若是像記憶力虛弱如我,常常追了後面幾千行、跳了三個檔,就忘了前面幾個檔案的函式名稱。於是常常輔助紙本畫流程圖,但是手繪圖往往不敵跳來繞去的程式碼邏輯。還是得靠程式碼解析視覺化工具來協助理解。

繪製 Call Graph 的工具非常多,一般可以分作 Dynamic analysisStatic analysis 兩種做法。在臺灣,最知名的商業版本工具,大概是 Source Insight。不過我不用 Windows,對於缺乏原始碼的開發工具興趣也不大。

開源的 Dynamic analysis 有像是 Jserv 介紹過CodeViz 或是 ncc。不過這類工具需要 patch gcc,不特別適合嵌入式系統專案。因爲原始碼常常只支援特定平臺,或是無法取得編譯工具原始碼,此外不同版本的 compiler 偶爾會造成不同的問題,造成使用上的困難。

一種比較乾淨的做法是像 KCachegrind 利用 valgrind 來收集資料,或 Gprof2Dot 利用 gprof 的輸出資料。再者是利用 gcc 的除錯功能,把 internal representation (RTL) 倒出來,再用egyptPython-RTL 來判讀或繪圖。

至於 Static analysisFred Chien 介紹過cflow 或是 Doxygen 也有類似的繪圖功能。也有工具是配合 cscopeglobal,例如有人幫 CScope 刻過圖形界面,Vim 有個 CCTree 可用。

CallGraphviz

以上這些工具各有優缺點。

最常見的問題是許多工具無法處理 function pointer / dynamic dispatch,最終還是要人力介入。另外一個使用上的困擾是,這些程式會一口氣畫出整個程式碼的結構圖。

太多資訊其實妨礙理解,因爲用途常常只是追一個臭蟲,程式開發者只想畫出特定路徑來釐清問題。而context-sensitive 的 call graph 測試工具又耗費資源。

若用 CodeLite, Code Blocks , Eclipse CDT 等開發工具,工具已經內建或整合 cscope /global,提供 symbol lookup 功能,於是開發者很容易用滑鼠查閱函式定義或實做,或也可以搭配 LXR 來瀏覽程式碼。已經不需要像是 cbrowser 專屬的程式碼瀏覽工具

所以需要的是可以手動的將目前程式情境視覺化的工具,網路上已經有其他開發者做了 Bash: C Call Trees and Graphs 或是 Global-calltree。或是像 ypwang方法,記錄函式進出點,再手動繪圖。

這些工具大多是整合 shell scripts,操作上有點不便。另外我也不喜歡 Call Tree 的圖式,因爲樹狀圖無法表現遞迴或交互關係。

於是查找一下,決定拿 cscope 加上 GraphvizDOT 語法來用,改了一個 CallGraphviz。它的功能是一個 Graphviz 前端,後端還是使用 cscope 查 symbols,為了可以即時瀏覽就拿了 xdot 當作界面。xdot 是以 PyGtk 開發,非常容易更改,不到三百行就加入我需要的功能。
 

使用方法

  • python visualizer.py
  • 按下 “New”, 選擇要分析 C/C++ 專案目錄。
  • 於 “Search symbol” 鍵入要追蹤的函式名稱。
  • 每次鍵入新名稱,他會自動對應圖中已輸入函式是否爲 caller or callee,並自動畫圖。

CallGraphviz 可以將繪圖結果存成 dot 格式檔案,然後再利用 dot 指令轉換格式。不過它只是把曾經查過的名稱記錄起來,開啟時重新查 cscope 而已,若圖大時,每次開啟可能會十分緩慢。

原始碼可於 github 下載,授權採用 GNU Lesser General Public License.

延伸閱讀
Python Call Graph