现在的位置: 首页 > 综合 > 正文

C代码阅读工具—calltrer

2018年04月15日 ⁄ 综合 ⁄ 共 3785字 ⁄ 字号 评论关闭

from: http://blog.sina.com.cn/s/blog_502c8cc4010115m5.html


最近在看一个开源代码bind过程中,该代码是由纯C语言编写的,函数间调用关系特别的复杂。想对整体代码有一个大概的了解,这样就需要了解代码中主要的相关函数间调用关系,发现一个开源的小工具calltree,在linux下能够将代码中函数调用关系生成调用树,并可以选择生成dot语言文件,通过dot工具生成调用关系图。下面介绍一下calltree工具:

calltree基本命令:calltree
-gb -np –m *.c

calltree所有的命令可以通过 calltree
–help
查看,如下图:

[root@localhost i686-linux-cc]# ./calltree -help

Usage:  calltree [calltree_options] [cpp_options] file1..filen

Options:

        -b              Print
a vertial Bar at each tab stop.

        -r              Invert
the structure of the tree.

        -f              Flattened
(cumulative) tree.

        -g              Print
file names past procedure names.

        -m              Call
structure for main only.

        -p              Use
C Preprocessor (default).

        -np             Don't
use C Preprocessor.

        -u              List
all functions not called via 'main'.

        -e              List
all functions not called.

        -x              List
all external functions.

        -xvcg           Format
output for xvcg.

        -dot            Format
output for graphviz.

        -v              Be
verbose.

        -help           Print
this help.

        -version        Print
version number.

        igorefile=file  Don't
list functions found in 'file'.

        listfile=file   List
only functions found in 'file'.

        list=name       Produce
call graph only for function 'name'.

        depth=#         Set
the maximum printed nesting depth to #.

        s=#             Set
indentation to #.

ignorefile=, listfile= and depth= may be abbreviated 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这个选项后,那么函数调用只显示两层调用关系,这样会对代码整体有个大概了解,阅读起来相对容易一些。

         main [named/main.c:808]:

|   UNEXPECTED_ERROR

|   cleanup [named/main.c:699]

|   |   destroy_managers
[named/main.c:528]

|   |   dlz_drivers_clear

|   |   dns_name_destroy

|   |   isc_log_write

|   |   ns_builtin_deinit
[named/builtin.c:305]

|   |   ns_log_shutdown
bin/named/log.c:231]

|   |   ns_server_destroy
[named/server.c:3639]

|   dns_result_register

|   dst_result_register

|   isc_app_finish

|   isc_app_run

那当我们通过depth选项后对程序main函数有一个整体把握后,想对其中main函数调用的某一个特定函数进行更细的分析,那么我们就用到了list=name选项。

list=name选项:例如我们通过查看上面的main函数调用关系图后,先更细的看看isc_app_run函数内部的调用关系,那么我们就会

 

isc_app_run [lib/isc/unix/app.c:430]:

|   ISC_LIST_HEAD

|   ISC_LIST_NEXT

|   ISC_LIST_UNLINK

|   LOCK [lib/isc/mem.c:41]

|   REQUIRE

|   UNEXPECTED_ERROR

|   UNLOCK [lib/isc/mem.c:43]

|   |   ISC_LINK

|   evloop [lib/isc/unix/app.c:300]

|   |   TIME_NOW

|   |   isc__socketmgr_dispatch
[lib/isc/unix/socket.c:3827]

|   |   isc__socketmgr_getfdsets
[lib/isc/unix/socket.c:3816]

|   |   isc__taskmgr_dispatch
[lib/isc/task.c:1251]

|   |   isc__taskmgr_ready
[lib/isc/task.c:1244]

|   |   isc__timermgr_dispatch
lib/isc/timer.c:923]

|   |   isc__timermgr_nextevent
[lib/isc/timer.c:915]

|   |   isc_time_microdiff
[lib/isc/unix/time.c:305]

|   |   select

|   exit

|   handle_signal [lib/isc/unix/app.c:102]

|   |   UNEXPECTED_ERROR

|   |   isc__strerror
[lib/isc/unix/strerror.c:47]

|   |   isc_msgcat_get

|   |   memset

|   |   sigaction

|   |   sigfillset

 

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选项后并画图,得出的图形太大,一般的图形工具无法展现,所以该功能变成无效。

     3、希望实现数据结构之间的包含关系。

 

参考:http://www.linuxsir.org/bbs/thread246389.html

抱歉!评论已关闭.