callgraph工具, 函数调用关系 | cflow, egypt 和 doxygen 使用
概述
作为一名linux嵌入式开发人员,长时间与linux打交道,多数情况工作在终端 + vim的环境下,已经习惯了文字界面。在阅读代码时,经常会在cscope中跳来跳去,但对于大型软件项目来说,这种情况就有些脑栈不够。闲来无事,研究下有什么工具可以生成函数调用图,来提高阅读代码的效率。能够实现代码调用的工具很多,经过研究cflow, egypt和doxygen丰富程度依次递增,可以基本满足不同层次的多数需求。
cflow
GNU cflow 分析 C 源文件的集合并打印图形,绘制程序中的控制流。GNU cflow能够为C源生成直接和反转的流图。(可选)可以生成交叉引用列表。实现了两种输出格式:POSIX 和 GNU(扩展)。
可以选择在分析之前对输入文件进行预处理。
优点:
- 输出树形文本调用关系:方便快捷,可以直接在终端内使用
- 不需要编译运行,静态分析
- 简单轻便:使用简单方便
- 函数位置是按照代码位置输出,方便查看
缺点:
- 不能跨文件分析:不能分析调用的外部函数
- 分析不够准确:如果存在宏嵌套等情况将无法分析走的分支
使用
安装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 脚本,它将这些现有工具粘合在一起。
优点:
- 软件小巧,易于使用
- 使用简单
缺点:
- 依赖编译生成的dump文件
- 不支持函数指针分析
- 生成结果依赖传入的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软件包为例:
- 增加或修改编译参数
-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
- 编译生成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
- 生成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,可以看到生成的内容非常的丰富。
优点:
- 功能强大,不仅可以生成代码调用关系
- 输出文件内容丰富:html,chm和pdf文件
- 配置容易,使用简单
还是以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
参考
- egypt | Egypt官网
- reveriel/callgraph: Call-graph generator. | 各种callgraph说明,但没有推荐和评分
- GNU cflow | 官方使用手册
本文来自博客园,作者:whilewell,转载请注明原文链接:https://www.cnblogs.com/viiv/p/15736106.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~