callgraph工具, 函数调用关系 | cflow, egypt 和 doxygen 使用

概述

作为一名linux嵌入式开发人员,长时间与linux打交道,多数情况工作在终端 + vim的环境下,已经习惯了文字界面。在阅读代码时,经常会在cscope中跳来跳去,但对于大型软件项目来说,这种情况就有些脑栈不够。闲来无事,研究下有什么工具可以生成函数调用图,来提高阅读代码的效率。能够实现代码调用的工具很多,经过研究cflow, egypt和doxygen丰富程度依次递增,可以基本满足不同层次的多数需求。

cflow

‎GNU cflow 分析 C 源文件的集合并打印图形,绘制程序中的控制流。‎‎GNU cflow能够为C源生成直接和反转的流图。(可选)可以生成交叉引用列表。实现了两种输出格式:POSIX 和 GNU(扩展)。‎
‎可以选择在分析之前对输入文件进行预处理。

优点:

  1. 输出树形文本调用关系:方便快捷,可以直接在终端内使用
  2. 不需要编译运行,静态分析
  3. 简单轻便:使用简单方便
  4. 函数位置是按照代码位置输出,方便查看

缺点:

  1. 不能跨文件分析:不能分析调用的外部函数
  2. 分析不够准确:如果存在宏嵌套等情况将无法分析走的分支

使用

安装cflow

sudo apt-get install cflow

以simple-tftp代码client.c中的main函数为例进行分析

wsk@wsk:~/test/simple-tftp$ cflow -Tn -m main client.c
    1 +-main() <int main (int argc, char *argv[]) at client.c:139>
    2   +-getopt()
    3   +-atoi()
    4   +-fprintf()
    5   +-exit()
    6   +-sprintf()
    7   +-printf()
    8   +-memset()
    9   +-getaddrinfo()
   10   +-gai_strerror()
   11   +-socket()
   12   +-perror()
   13   +-connect()
   14   +-close()
   15   +-inet_ntop()
   16   +-get_in_addr() <void *get_in_addr (struct sockaddr sa) at client.c:130>
   17   +-fcntl()
   18   +-bzero()
   19   +-fopen()
   20   +-strcpy()
   21   +-fill_header()
   22   +-fill_packet()
   23   +-add_checksum()
   24   +-htons()
   25   +-tftp() <int tftp (int sockfd, const void *packet, int expected_seqnum, int timeout, int flag) at client.c:44>
   26   | +-send()
   27   | +-perror()
   28   | +-exit()
   29   | +-printf()
   30   | +-recvfromTimeOut() <int recvfromTimeOut (int socket, long sec, long usec) at client.c:29>
   31   | | +-FD_ZERO()
   32   | | +-FD_SET()
   33   | | \-select()
   34   | +-recv()
   35   | \-read_header()
   36   +-fclose()
   37   +-fread()
   38   \-freeaddrinfo()

还可以查看反向调用

    1 +-FD_SET()
    2   \-recvfromTimeOut() <int recvfromTimeOut (int socket, long sec, long usec) at client.c:29>
    3     \-tftp() <int tftp (int sockfd, const void *packet, int expected_seqnum, int timeout, int flag) at client.c:44>
    4       \-main() <int main (int argc, char *argv[]) at client.c:139>
    5 +-FD_ZERO()
    6   \-recvfromTimeOut() <int recvfromTimeOut (int socket, long sec, long usec) at client.c:29> [see 2]
    7 +-add_checksum()
    8   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
    9 +-atoi()
   10   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   11 +-bzero()
   12   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   13 +-close()
   14   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   15 +-connect()
   16   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   17 +-exit()
   18   +-tftp() <int tftp (int sockfd, const void *packet, int expected_seqnum, int timeout, int flag) at client.c:44> [see 3]
   19   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   20 +-fclose()
   21   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   22 +-fcntl()
   23   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   24 +-fill_header()
   25   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   26 +-fill_packet()
   27   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   28 +-fopen()
   29   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   30 +-fprintf()
   31   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   32 +-fread()
   33   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]
   34 +-freeaddrinfo()
   35   \-main() <int main (int argc, char *argv[]) at client.c:139> [see 4]

egypt

Egypt 是一个用于创建 C 程序调用图的简单工具。 Egypt既不分析源代码也不布置图表。 相反,它将源代码分析留给 GCC,将图形布局留给 Graphviz,这两者在各自的工作中都比Egypt本身所希望的要好。 Egypt只是一个非常小的 Perl 脚本,它将这些现有工具粘合在一起。

优点:

  1. 软件小巧,易于使用
  2. 使用简单

缺点:

  1. 依赖编译生成的dump文件
  2. 不支持函数指针分析
  3. 生成结果依赖传入的dump文件

使用

使用路径:gcc生成dump文件 --> Egypt解析dump文件后生成dot --> Graphviz将dot生成图表
安装Graphviz

sudo apt-get install graphviz

安装Egypt

解压Egypt软件包后进入到目录中
perl Makefile.PL
make
sudo make install

然后以simple-tftp软件包为例:

  1. 增加或修改编译参数-fdump-rtl-expand
wsk@wsk:~/test/simple-tftp$ git diff Makefile
diff --git a/Makefile b/Makefile
index 25e88db..2d1e7c9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-CC = gcc
+CC = gcc -fdump-rtl-expand

 all: client server
  1. 编译生成dump文件*.expand
wsk@wsk:~/test/simple-tftp$ ls
callgraph.svg  checksum.c.229r.expand  checksum.o  client.c              header.c              header.h  Makefile   server    server.c.229r.expand
checksum.c     checksum.h              client      client.c.229r.expand  header.c.229r.expand  header.o  Readme.md  server.c
  1. 生成svg图片
    这里面分成3中情况进行生成:
    case 1:全部的expand生成在一起
    case 2:仅包含client的(simple-tftp软件包会编译出两个程序client和server)
    case 3:仅包含server的(simple-tftp软件包会编译出两个程序client和server)
    对应的命令
case 1:
egypt *.expand | dot -Grankdir=LR -Tsvg -o callgraph.svg
case 2:
egypt client.c.229r.expand checksum.c.229r.expand header.c.229r.expand | dot -Grankdir=LR -Tsvg -o client.svg
case 3:
egypt server.c.229r.expand checksum.c.229r.expand header.c.229r.expand | dot -Grankdir=LR -Tsvg -o server.svg

生成的svg图表对比
【case 1】全部的dump

【case 2】client dump

【case 3】server dump

通过对比和分析,可以有初步的结果:

  • 系统函数显示不出来(分析client svg)
  • 传入不同的dump文件,显示的结果会有不同

doxygen

doxygen可以生成项目文档不仅包含调用关系,详见下面gjf,可以看到生成的内容非常的丰富。

优点:

  1. 功能强大,不仅可以生成代码调用关系
  2. 输出文件内容丰富:html,chm和pdf文件
  3. 配置容易,使用简单

还是以simple-tftp工程为例
安装doxygen

sudo apt-get install doxygen
sudo apt-get install graphviz

生成Doxyfile

进入到项目目录
doxygen -g

配置Doxyfile:(下面的修改也可以自己封装成脚本来实现)。下面的配置仅包含常用参数,有需要可以细看Doxyfile中的备注

需要设置YES的变量
HAVE_DOT
EXTRACT_ALL
EXTRACT_PRIVATE
EXTRACT_STATIC
CALL_GRAPH
OPTIMIZE_OUTPUT_FOR_C
RECURSIVE

下面参数按需配置:
INPUT:源码位置 | 按需修改
  1. 为空时表示源码在当前位置
  2. 支持多路径,路径间用空格隔开
GENERATE_HTML:是否生成html。生成html后可以通过web进行访问 | 建议开启
GENERATE_HTMLHELP:是否生成压缩HTML格式文档(.chm) | 按需开启
EXTRACT_LOCAL_CLASSES:是否解析源文件(cpp文件)中定义的类 | 按需开启
SOURCE_BROWSER:如果设定为YES,则Doxygen会产生出源文件的列表,以供查阅。 | 按需开启

执行命令创建:

doxygen Doxyfile
执行完成后,会生成html目录

创建http server:

进入到html目录
python3 -m http.server 8000

8000:是端口,可以按需修改

浏览内容:

浏览器中访问http://$hostip:8000

附件

《Doxygen v1.63 中文手册.pdf》链接: https://pan.baidu.com/s/1ptS6B4ovA911TzSDb3YtlQ?pwd=nwu4 提取码: nwu4

参考

posted @ 2021-12-27 14:26  whilewell  阅读(2755)  评论(1编辑  收藏  举报