平時用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