【转载】C代码阅读工具(1)---calltrer

7 篇文章 0 订阅

C代码阅读工具(1)---calltrer

作者:李明华


最近在看一个开源代码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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生参加学科竞赛有着诸多好处,不仅有助于个人综合素质的提升,还能为未来职业发展奠定良好基础。以下是一些分析: 首先,学科竞赛是提高专业知识和技能水平的有效途径。通过参与竞赛,学生不仅能够深入学习相关专业知识,还能够接触到最新的科研成果和技术发展趋势。这有助于拓展学生的学科视野,使其对专业领域有更深刻的理解。在竞赛过程中,学生通常需要解决实际问题,这锻炼了他们独立思考和解决问题的能力。 其次,学科竞赛培养了学生的团队合作精神。许多竞赛项目需要团队协作来完成,这促使学生学会有效地与他人合作、协调分工。在团队合作中,学生们能够学到如何有效沟通、共同制定目标和分工合作,这对于日后进入职场具有重要意义。 此外,学科竞赛是提高学生综合能力的一种途径。竞赛项目通常会涉及到理论知识、实际操作和创新思维等多个方面,要求参赛者具备全面的素质。在竞赛过程中,学生不仅需要展现自己的专业知识,还需要具备创新意识和解决问题的能力。这种全面的综合能力培养对于未来从事各类职业都具有积极作用。 此外,学科竞赛可以为学生提供展示自我、树立信心的机会。通过比赛的舞台,学生有机会展现自己在专业领域的优势,得到他人的认可和赞誉。这对于培养学生的自信心和自我价值感非常重要,有助于他们更加积极主动地投入学习和未来的职业生涯。 最后,学科竞赛对于个人职业发展具有积极的助推作用。在竞赛中脱颖而出的学生通常能够引起企业、研究机构等用人单位的关注。获得竞赛奖项不仅可以作为个人履历的亮点,还可以为进入理想的工作岗位提供有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值