開源工具現狀

許多開發者都有介入中大型專案的經驗,常必須試圖理解原始程式的設計,或多或少都有在程式碼迷宮中找路的經驗。有些專案,程式碼結構嚴謹,軟體設計應用 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