1. 程式人生 > >繪製函式呼叫圖(call graph)(2):cflow + graphviz

繪製函式呼叫圖(call graph)(2):cflow + graphviz

專欄導讀

本專欄第一篇文章「專欄開篇」列出了專欄的完整目錄,按目錄順序閱讀,有助於你的理解。

前言

cflow是一款靜態分析C語言程式碼的工具,通過它可以生成函式呼叫關係。

如果你英文可以,上面的手冊就是很好的使用教程,本文只是簡單的介紹下如何使用cflow,旨在讓新手快速入門cflow而已。

安裝cflow

在linux下安裝cflow很簡單,如下是我在Ubuntu下的安裝命令:

# sudo apt-get install cflow
#
# cflow --version
cflow (GNU cflow) 1.4
Copyright (C) 2005, 2006, 2009, 2010
, 2011 2009 Sergey Poznyakoff License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Sergey Poznyakoff.

通過以下命令檢視使用說明:

# cflow --help

由於cflow以來gawk,你的環境有可能是mawk,所以還得安裝下gawk:

# sudo apt-get install gawk

使用cflow分析函式呼叫關係

舉個簡單的例子,以下是原始檔whoami.c內容(原始碼來自官網手冊):

/* whoami.c - a simple implementation of whoami utility */
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>

int who_am_i(void)
{
    struct passwd *pw;
    char
*user = NULL; pw = getpwuid (geteuid ()); if (pw) user = pw->pw_name; else if ((user = getenv ("USER")) == NULL) { fprintf (stderr, "I don't know!\n"); return 1; } printf ("%s\n", user); return 0; } int main(int argc, char **argv) { if (argc > 1) { fprintf (stderr, "usage: whoami\n"); return 1; } return who_am_i (); }

執行cflow將生成以下輸出:

# cflow whoami.c 
main() <int main (int argc, char **argv) at whoami.c:24>:
    fprintf()
    who_am_i() <int who_am_i (void) at whoami.c:7>:
        getpwuid()
        geteuid()
        getenv()
        fprintf()
        printf()

cflow預設是分析main函式,可以通過 -m 選項分析其他函式:

# cflow -m who_am_i whoami.c 
who_am_i() <int who_am_i (void) at whoami.c:7>:
    getpwuid()
    geteuid()
    getenv()
    fprintf()
    printf()

cflow只能以ASCII文字的形式輸出函式呼叫關係,不能輸出圖片格式,對於大型專案的程式碼來說,龐雜的文字輸出簡直“慘不忍睹,無法直視”。需要其他工具的輔助,才能將本文格式轉化為可讀性更強的圖片格式,大致步驟如下:

  1. cflow工具:輸出文字格式的函式呼叫關係;
  2. tree2dotx指令碼:將文字格式轉化為dot格式;
  3. graphviz工具:將dot格式轉化為圖片格式;

從文字檔案轉為dot檔案

將cflow輸出的文字檔案轉化為dot格式的工具有tree2dotx,是否有其他工具,有待研究。通過以下命令下載tree2dotx指令碼:

# wget -c https://github.com/tinyclub/linux-0.11-lab/raw/master/tools/tree2dotx -O /usr/bin/tree2dotx
# chmod +x /usr/bin/tree2dotx

將cflow輸出的文字檔案轉化為dot格式:

# cflow whoami.c | tree2dotx > out.dot

從dot檔案轉為圖片檔案

安裝graphviz:

# sudo apt-get install graphviz

將dot格式轉化為圖片格式:

# dot -Tgif out.dot -o out.gif

最終生成的影象如下所示:


這裡寫圖片描述

可以看出,連繫統函式printf都顯示出來了,這往往不是我們所關心的,有沒有什麼辦法可以忽略這些系統函式呢?我還沒找到方法,有知道的誠盼您的留言指教。

其他補充

  • 問:cflow能同時分析一個原始檔中多個函式的call graph嗎?
  • 答:cflow預設只分析main函式的call graph,如果main不存在,將分析該檔案的所有函式。可以通過 -m 選項分析指定的函式,如果指定的函式不存在,也會分析該檔案的所有函式。可以利用這個特點,通過 -m 指定一個空的函式名,讓cflow分析所有函式的call graph,如:
# cflow -m= file1.c
  • 問:cflow可以同時分析多個原始檔嗎?
  • 答:可以,使用如下兩種命令都可以:
# cflow -m= file1.c file2.c
# cflow -m= *.c

需要注意的是,如果多個原始檔出現同名函式,cflow會警告,並且只分析其中一個main函式。

  • 問:cflow可以分析整個目錄(包括子目錄)的原始檔嗎?
  • 答:通過 cflow –help 檢視幫助,我沒找到有這方面的選項。

總結

做個簡單的總結:

  1. 使用cflow工具,分析原始碼,得到文字格式的函式呼叫關係;
  2. 使用tree2dotx指令碼,將文字格式轉化為dot格式;
  3. 使用graphviz工具,視覺化函式呼叫,將dot格式轉化為圖片格式;