平时用vim+cscope+ctags看程序还不错,但跳来跳去还是不太直观,如果能将C代码的调用生成调用树就再好不过了,果然,偶找到了一款不错的工具calltree,有了这个工具,可以说宏观微宏一起把握了,
先看一下用它生成的函数调用图:
源码是nbtscan小工具的代码.
ljt@debian:~/source/nbtscan-1.5.1$ calltree -gb -np -m *.c
main [nbtscan.c:289]:
| FD_ISSET
| FD_SET
| FD_ZERO
| atoi
| bind
| bzero
| d_print_hostinfo [nbtscan.c:93]
| | inet_ntoa
| | printf
| | strncpy
| delete_list [list.c:29]
| | free
| err_die
| err_print
| exit
| feof
| fgets
| fopen
| fprintf
| free
| getopt
| gettimeofday
| htons
| in_list [list.c:101]
| | compare [list.c:47]
| | new_list_item [list.c:17]
| | | err_die
| | | malloc
| inet_aton
| inet_ntoa
| insert [list.c:55]
| | compare [list.c:47]
| | free
| | new_list_item [list.c:17]
| | | err_die
| | | malloc
| l_print_hostinfo [nbtscan.c:260]
| | inet_ntoa
| | printf
| | strncpy
| malloc
| new_list [list.c:8]
| | err_die
| | malloc
| next_address [range.c:72]
| | htonl
| | ntohl
| ntohl
| parse_response [statusq.c:147]
| | bzero
| | get16 [statusq.c:137]
| | | memcpy
| | | ntohs
| | get32 [statusq.c:127]
| | | memcpy
| | | ntohl
| | malloc
| | memcpy
| | strncpy
| | typeof
| print_banner [nbtscan.c:26]
| | printf
| print_header [nbtscan.c:87]
| | printf
| print_hostinfo [nbtscan.c:207]
| | inet_ntoa
| | printf
| | strncpy
| printf
| recvfrom
| select
| send_query [statusq.c:93]
| | bzero
| | err_print
| | gettimeofday
| | htons
| | inet_ntoa
| | name_mangle [statusq.c:40]
| | | HAVE_SNPRINTF
| | | memset
| | | snprintf
| | | sprintf
| | | strcmp
| | | strlen
| | | toupper
| | sendto
| | snprintf
| set_range [nbtscan.c:80]
| | is_ip [range.c:21]
| | | inet_addr
| | | ntohl
| | is_range1 [range.c:36]
| | | abs
| | | atoi
| | | err_die
| | | free
| | | inet_addr
| | | malloc
| | | ntohl
| | | strchr
| | | strcpy
| | | strlen
| | is_range2 [range.c:91]
| | | atoi
| | | err_die
| | | free
| | | inet_addr
| | | malloc
| | | ntohl
| | | strchr
| | | strcpy
| | | strlen
| sleep
| snprintf
| socket
| strcmp
| strdup
| timerclear
| timercmp
| timersub
| usage [nbtscan.c:32]
| | exit
| | printf
| v_print_hostinfo [nbtscan.c:156]
| | getnbservicename [statusq.c:370]
| | | err_die
| | | malloc
| | | snprintf
| | | strstr
| | inet_ntoa
| | printf
| | strncpy
还不错哦,能很直观地显示程序的架构
下面介绍一下各选项:
ljt@debian:~/source/nbtscan-1.5.1$ calltree -gb -np -m *.c
-b 就是那个竖线了,很直观地显示缩进层次。
-g 打印内部函数的所属文件名及行号,外部函数所属文件名和行号也是可打印的,详man
-np 不要调用c预处理器,这样打印出的界面不会很杂乱,但也可能会产生错误哦,如果我们只看
函数的调用关系的话,不会有大问题。
-m 告诉程序从main开始
还有一个重要的选项是 listfunction ,缩写是lf,用来只打印某个函数中的调用,用法是:
$calltree -gb -np lf=send_query *.c
send_query [statusq.c:93]:
| bzero
| err_print
| gettimeofday
| htons
| inet_ntoa
| name_mangle [statusq.c:40]
| | HAVE_SNPRINTF
| | memset
| | snprintf
| | sprintf
| | strcmp
| | strlen
| | toupper
| sendto
| snprintf
还有几个不太常用的就不介绍了,细节大家还是看man吧,另外说明一点的是,安装的时候它默认是安装到"/opt/schily/"目录下,下面有bin, man, include等几个目录,你可以设置环境变量,或者干脆把它拷贝到/usr里相应的目录下,或者修改Makefile啦
下载地址:
ftp://ftp.berlios.de/pub/calltree/calltree-2.3.tar.bz2