您的位置:首页 > 编程语言

C代码阅读工具---calltrer

2011-12-16 20:36 246 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: