1. 程式人生 > >靜態分析C語言生成函式呼叫關係的利器——cflow

靜態分析C語言生成函式呼叫關係的利器——cflow

        除了《靜態分析C語言生成函式呼叫關係的利器——calltree》一文中介紹的calltree,我們還可以藉助cflow輔助我們閱讀理解程式碼。(轉載請指明出於breaksoftware的csdn部落格)

cflow的說明和安裝

        cflow是一款靜態分析C語言程式碼的工具,通過它可以生成函式的呼叫關係。和calltree不一樣,cflow有獨立的網頁介紹它(https://www.gnu.org/software/cflow/#TOCdocumentation)。而且在Ubuntu系統上,我們可以不用去編譯cflow的原始碼,而直接使用下面命令獲取

apt-get install cflow

cflow的使用

        安裝完畢,我們可以使用下面指令看到cflow的引數說明

cflow --help
        我們可以得到如下提示
Usage: cflow [OPTION...] [FILE]...
generate a program flowgraph

 General options:
  -d, --depth=NUMBER         Set the depth at which the flowgraph is cut off
  -f, --format=NAME          Use given output format NAME. Valid names are
                             `gnu' (default) and `posix'
  -i, --include=CLASSES      Include specified classes of symbols (see below).
                             Prepend CLASSES with ^ or - to exclude them from
                             the output
  -o, --output=FILE          Set output file name (default -, meaning stdout)
  -r, --reverse              * Print reverse call tree
  -x, --xref                 Produce cross-reference listing only

 Symbols classes for --include argument

    _                        symbols whose names begin with an underscore
    s                        static symbols
    t                        typedefs (for cross-references only)
    x                        all data symbols, both external and static

 Parser control:

  -a, --ansi                 * Accept only sources in ANSI C
  -D, --define=NAME[=DEFN]   Predefine NAME as a macro
  -I, --include-dir=DIR      Add the directory DIR to the list of directories
                             to be searched for header files.
  -m, --main=NAME            Assume main function to be called NAME
  -p, --pushdown=NUMBER      Set initial token stack size to NUMBER
      --preprocess[=COMMAND], --cpp[=COMMAND]
                             * Run the specified preprocessor command
  -s, --symbol=SYMBOL:[=]TYPE   Register SYMBOL with given TYPE, or define an
                             alias (if := is used). Valid types are: keyword
                             (or kw), modifier, qualifier, identifier, type,
                             wrapper. Any unambiguous abbreviation of the above
                             is also accepted
  -S, --use-indentation      * Rely on indentation
  -U, --undefine=NAME        Cancel any previous definition of NAME

 Output control:

  -b, --brief                * Brief output
      --emacs                * Additionally format output for use with GNU
                             Emacs
  -l, --print-level          * Print nesting level along with the call tree
      --level-indent=ELEMENT Control graph appearance
  -n, --number               * Print line numbers
      --omit-arguments       * Do not print argument lists in function
                             declarations
      --omit-symbol-names    * Do not print symbol names in declaration strings
                            
  -T, --tree                 * Draw ASCII art tree

 Informational options:

      --debug[=NUMBER]       Set debugging level
  -v, --verbose              * Verbose error diagnostics

  -?, --help                 give this help list
      --usage                give a short usage message
  -V, --version              print program version

Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.

* The effect of each option marked with an asterisk is reversed if the option's
long name is prefixed with `no-'. For example, --no-cpp cancels --cpp.

Report bugs to <
[email protected]
>.

        我只列出我覺得有意思的幾個引數:

        -T輸出函式呼叫樹狀圖

        -m指定需要分析的函式名

        -n輸出函式所在行號

        -r輸出呼叫的反向關係圖

        --cpp預處理,這個還是很重要的

文字輸出

        最簡單的使用方法是以ASCII文字的方式輸出結果,比如

cflow -T -m main -n timer.c
        其結果是一個包含檔名和函式所在程式碼行號的呼叫關係圖
+-main() <int main (void) at timer.c:13>
  +-ev_timer_init()
  +-timeout_cb() <void timeout_cb (EV_P_ ev_timer *w, int revents) at timer.c:7>
  | +-puts()
  | \-ev_break()
  +-ev_timer_start()
  \-ev_run()

        然而,對於有一定程式碼量的專案,我們不會使用ASCII文字的方式去檢視函式呼叫關係,因為呼叫是相當複雜的,而文字圖並不適合人去理解。於是我們希望能cflow能產出一個可供其他軟體轉換成圖片的格式的檔案。可惜cflow並不支援,好在網上有開發者做了一個工具,可將其結果轉換成dot格式。

轉成dot檔案

        我們可以使用下面方法獲取轉換工具
wget -c https://github.com/tinyclub/linux-0.11-lab/raw/master/tools/tree2dotx
        下載完tree2dotx後,可對其做個軟鏈便於使用
cd /usr/bin
ln -s 【Your Path】/tree2dotx tree2dotx

        具體的轉換方法是

cflow -T -m main -n timer.c > main.txt
cat main.txt | tree2dotx > main.dot

dot檔案生成圖片        

        我們需要藉助graphviz(沒有安裝的可以使用apt-get install graphviz先安裝)生成圖片,指令是

dot -Tgif main.dot -o main.gif