一、基于 Doxygen或 lxr 的API形式的文档系统。
二、基于CodeViz, CodeViz是《Understanding The Linux Virtual Memory Manager》的作者 Mel Gorman 写的一款分析C/C++源代码中函数调用关系的open source工具(类似的open source软件有 egypt、ncc)。属于编译器级别的分析工具。
三、基于cflow、dot(即graphviz)等系列软件。属于源码直接解析类的分析工具。
四、基于egypt, 比较推荐这个,因为它支持 arm。它不用大动干戈地给编译器打补丁,而是让编译器自己dump出调用关系,然后分析分析,交给Graphviz去绘图。属于编译器级别的分析工具。
一、略。
二、基于CodeViz,主要是Graphviz + CodeViz,一个分析,一个画图。
三、基于cflow、dot(graphviz)。用于源码分析比较合适,无法从编译器视角去分析。参看:
www.tinylab.org/callgraph-draw-the-calltree-of-c-functions/?utm_source=tuicool&utm_medium=referral
值得说明的是,cflow无法直接对目录进行recursive分析,它只支持文件分析,即必须手动把要分析的文件指定给它,如: cflow -b -m fib ./h/fib.c ./cc/fi.c ./ccc/fi.c
而且,如果 ./h/fib.c ./cc/fi.c ./ccc/fi.c 中有重名的函数,则这些同名函数的调用关系会合并,即若./cc/fi.c 中有个函数a只调用了函数b,而./ccc/fi.c中也有个函数a只调用了函数c,则最后打印出来的结果是函数a同时调用了b和c,即合并了。
对于cflow系列工具的使用,因为它输出的不是图形化的调用关系,因此这里推荐使用www.tinylab.org的组合工具:calltree。 它整合了cflow及graphviz并附带了一个将C 函数调用树转换为 dot 格式的脚本:tree2dotx:
以 Ubuntu 为例,分别安装它们:
$ sudo apt-get install cflow graphviz
$ wget -c https://github.com/tinyclub/linux-0.11-lab/raw/master/tools/tree2dotx $ wget -c https://github.com/tinyclub/linux-0.11-lab/raw/master/tools/callgraph $ sudo cp tree2dotx callgraph /usr/local/bin $ sudo chmod +x /usr/local/bin/{tree2dotx,callgraph}
$ sudo apt-get install gawk
我已经把tree2dotx 及 callgraph 放入到了自己的云盘
使用方法:
$ callgraph -f start_kernel -d init/main.c #只在文件init/main.c里打印函数start_kernel里的所有调用关系图
$ callgraph -f start_kernel -d init/main.c -F printk #可用 -F
过滤掉不需要打印的函数
$ callgraph -f start_kernel -d init/main.c -F "printk boot_cpu_init rest_init" #可用 -F
过滤掉不需要打印的多个函数
$ callgraph -f start_kernel -d init/main.c -F "printk boot_cpu_init rest_init" -D 2 # 用 -D 指定函数的搜索深度(同一个文件的)
由于callgraph这个脚本也无法对目录进行递归统计(cflow也无法),且callgraph用*(全部匹配)这种方法不起作用,但cflow用*方法可以匹配所有文件但不能匹配目录:
$ callgraph -f start_kernel -d init/*$ cflow -b -m main example/* | /usr/local/bin/tree2dotx 2>/dev/null | dot -Tsvg -o ./main.svg # 档example目录里没有任何目录(即全是文件)时才能执行成功, # 若有任何目录,则执行失败$ cflow -b example/* | /usr/local/bin/tree2dotx 2>/dev/null | dot -Tsvg -o ./main.svg # 不带 -m 选项,将列出所有函数的调用关系$ cflow -b example/* | /usr/local/bin/tree2dotx -f "printk boot_cpu_init rest_init" 2>/dev/null | dot -Tsvg -o ./main.svg # 可以过滤掉 printk boot_cpu_init rest_init 函数的显示
因此有两种方法可以做到统计目录里的所有文件:一是修改callgraph这个脚本;二是手动列出example目录下的所有文件(包含子目录)输给cflow。
趣玩 tree2dotx
打印目录结构:
$ tree -L | tree2dotx | dot -Tsvg -o tree.svg
四、基于egypt
注意,可以在CFLAGS中加入的-O0参数,禁止编译器优化。如果不禁止优化,有些函数可能会因为优化的关系而显示不出来。
编译时加入:
CFLAGS = $(CFLAGS) -fdump-rtl-expand
编译结束后,假设所有的 expand文件都位于 expand_dir 目录,则可以这样生成dot文件:
egypt expand_dir/* > example.dot若只想用一部分文件来生成调用图,则可以指定文件:
egypt expand_dir/f1.c.144r.expand expand_dir/f2.c.184r.expand > example.dot
然后生成svg图片:dot example.dot -Tsvg -o example.svg
用 -Tpng 替换 -Tsvg 可以生成png图片,不过建议生成svg图片,因为它缩放不变形不模糊。
注意:如果函数太多,dot转换后的图片太大会打开失败,遇到这种情况可以使用dot的plain或者plain-ext格式来保存为纯文本(文本里的node指的是节点,edge指的是边,即指向),然后在纯文本里找到那些不需要的函数,重新用egypt的--omit去掉一些不需要的函数,直到dot转换后的图片能打开为止。或者直接看plain文本也可以。 纯文本里面的 solid ellipse black lightgrey 这些颜色、形状表示的是node或者edge的特征。
egypt 的命令格式:
egypt [--omit function,function,...] [--include-external] <rtl-file>... | dotty - egypt [--omit function,function,...] [--include-external] <rtl-file>... | dot <dot-options> omit
-
Omit the given functions from the call graph. Multiple function names may be given separated by commas.
- include-external
-
Include calls to external functions in the call graph. A function is considered external if it is not defined in any of the input files. For example, functions in the standard C library are external. Only direct function calls will be displayed; there is no way to display the action of taking the address of an external function.
还有一个基于 egypt 的比较好用的分析工具: https://github.com/cbdevnet/rtl2dot/