C代码阅读工具---calltrer

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
迅捷是一个功能强大的C/C++源代码阅读和维护软件。可以处理数百万行的源程序代码。支持标准及K&R风格的C/C++。对每一个打开的源代码工程,通过建立一个包含丰富交叉引用关系的数据库,显示其所含的各种信息:所有的源文件、所有的头文件、所有的代码文件、词汇索引、索引结果、文件包含关系、宏定义、数据结构和函数定义、可扩展的函数定义、函数调用关系、分文件夹的定义目录、构造层次、诊断性输出等。仅须按一键就可以非常方便地扩展各种类型的定义和调用关系。所有这些结合起来帮助用户快速地阅读、理解、研究和维护中大型源代码工程。 包含各种友好的用户界面效果,如对窗口的标签化排列、任意分隔、自动隐藏、浮动、拖拉等。可以使用户快速地找到每一个功能性窗口并重新以各种格局加以任意组合。 包含有一个多功能的文本及十六进制编辑器。便利性特色包括:句法着色、自动完成词汇、对整个内容的自动格式化对比于未经格式化可以提高可读性。可以动态地显示一个文件中的级联标示词。可以设置多个文件定义来指定对文件的处理、颜色及样式等。对FTP文件的处理如同本地文件一样。 包含一个可以同时打开多个工程的工作区,有许多命令可以处理某一个或所有的工程。有强大的功能可以同时在多个文件、文件夹、工程中进行后台查找和替换。 包含一个比较模块,可以进行文件之间或文件夹之间的后台对比。提供有许多命令来显示目标之间的差别。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值