作者:李明华
最近在看一个开源代码bind过程中,该代码是由纯C语言编写的,函数间调用关系特别的复杂。想对整体代码有一个大概的了解,这样就需要了解代码中主要的相关函数间调用关系,发现一个开源的小工具calltree,在linux下能够将代码中函数调用关系生成调用树,并可以选择生成dot语言文件,通过dot工具生成调用关系图。下面介绍一下calltree工具:
calltree基本命令:calltree -gb -np –m *.c
calltree所有的命令可以通过calltree–help查看,如下图:
[root@localhost i686-linux-cc]# ./calltree-help
Usage:
Options:
ignorefile=, listfile= and depth= may beabbreviated by first letter.
list= may be abbreviated by lf=.
注:该地方不明白为什么使用l表示listfil,而lf用于作为list的缩写。
下面我们主要介绍几个常用的选项:
-b 就是那个竖线了,很直观地显示缩进层次。
-g 打印内部函数的所属文件名及行号,外部函数所属文件名和行号也是可打印的,详man
-np 不要调用c预处理器,这样打印出的界面不会很杂乱,但也可能会产生错误哦,如果我们只看函数的调用关系的话,不会有大问题。
-m 告诉程序从main开始。
下面我们结合bind来说一下另外几个可能会用到的选项:
depth=#选项:当我们使用calltree -gb -np –m*.c,然后会发现函数特别多,就只在named目录下所有的.c文件,一共就几百个函数相互调用,这样我们阅读起来会非常的费劲,而我们只想了解main函数主要调用了哪几个相关的函数时,我们就需要用到depth选项。
例如:
./calltree -gb -np -m bind9/bin/named/*.[c.h]depth=2 > codecalltree.txt
> codecalltree.txt主要是因为函数调用关系较多,直接显示在终端上将无法查看,所以需要将内容导出到文本文件。
我们使用depth这个选项后,那么函数调用只显示两层调用关系,这样会对代码整体有个大概了解,阅读起来相对容易一些。
|
|
|
|
|
|
|
|
|
|
|
|
|
那当我们通过depth选项后对程序main函数有一个整体把握后,想对其中main函数调用的某一个特定函数进行更细的分析,那么我们就用到了list=name选项。
list=name选项:例如我们通过查看上面的main函数调用关系图后,先更细的看看isc_app_run函数内部的调用关系,那么我们就会
isc_app_run [lib/isc/unix/app.c:430]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dot选项:最后再介绍一个-dot选项,该选项可以将函数调用关系二维图形化。
例如:
./calltree -gb -np –m ./bind9/bin/named/*.c -dot> named_calltree.dot
生成的dot文件后,使用graphviz工具将dot文件转成图片并保存。
http://www.graphviz.org/pub/graphviz/stable/windows/graphviz-2.28.0.msi
不足之处:
1、获取的函数没有带上函数参数,不能将函数参数体现出来
2、函数数量太多时,使用dot选项后并画图,得出的图形太大,一般的图形工具无法展现,所以该功能变成无效。
参考:http://www.linuxsir.org/bbs/thread246389.html
联系客服