繪製函式呼叫圖(call graph)(2):cflow + graphviz
阿新 • • 發佈:2019-01-05
專欄導讀
本專欄第一篇文章「專欄開篇」列出了專欄的完整目錄,按目錄順序閱讀,有助於你的理解。
前言
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文字的形式輸出函式呼叫關係,不能輸出圖片格式,對於大型專案的程式碼來說,龐雜的文字輸出簡直“慘不忍睹,無法直視”。需要其他工具的輔助,才能將本文格式轉化為可讀性更強的圖片格式,大致步驟如下:
- cflow工具:輸出文字格式的函式呼叫關係;
- tree2dotx指令碼:將文字格式轉化為dot格式;
- 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 檢視幫助,我沒找到有這方面的選項。
總結
做個簡單的總結:
- 使用cflow工具,分析原始碼,得到文字格式的函式呼叫關係;
- 使用tree2dotx指令碼,將文字格式轉化為dot格式;
- 使用graphviz工具,視覺化函式呼叫,將dot格式轉化為圖片格式;