logo资料库

Cflow使用详解.pdf

第1页 / 共31页
第2页 / 共31页
第3页 / 共31页
第4页 / 共31页
第5页 / 共31页
第6页 / 共31页
第7页 / 共31页
第8页 / 共31页
资料共31页,剩余部分请下载后查看
Cflow 使用详解 朝歌 译 2014-11-8
目录 1、cflow 简介 ..................................................................................................................... 3 2、使用 cflow 分析程序的简要方法 .................................................................................. 3 3、两种类型的流图............................................................................................................. 5 4、各种输出格式 ................................................................................................................ 7 5、处理递归调用 ................................................................................................................ 8 6、控制符号类型 .............................................................................................................. 12 6.1、语法类 ................................................................................................................... 15 6.2、符号别名 ............................................................................................................... 16 6.3、GCC 初始化 .......................................................................................................... 16 7、运行预处理器 .............................................................................................................. 17 8、使用 ASCII 码来生成流图 ........................................................................................... 18 9、交叉引用输出 .............................................................................................................. 20 10、配置文件和变量 ........................................................................................................ 21 11、在 Makefiles 中使用 cflow ...................................................................................... 22 12、cflow 选项的完整列表 .............................................................................................. 23 13、GNU Emacs 使用 cflow .......................................................................................... 26 14、附录 wc 命令的源文件 .............................................................................................. 28
1、cflow 简介 cflow 工具用于分析 C 语言实现的源文件集并输出各个函数之间的依赖关系图。 cflow 可以生成两种类型的图:正向图和逆向图。正向图从 main()函数开始,递 归显示 main()函数调用的所有函数。相反,逆向图是一个子图的集合,使用递 归命令时,为每个函数列出它的调用者。 除了这两种输出模式,cflow 也可以为输入文件中的所有遇到的符号生成一个交 叉引用列表。 该程序还提供了对将出现在输出中出现的符号的详细控制,允许忽略用户不感兴 趣的符号。详细的输出格式也是可配置的。 2、使用 cflow 分析程序的简要方法 我们先从一个例子开始熟悉 GNU cflow 的用法。假设你已经有了一个 whoami 命令的简单实现,并且你想获得它的函数依赖关系图。下面的是程序: /* whoami.c - a simple implementation of whoami utility */ #include #include #include #include int who_am_i (void) { struct passwd *pw; char *user = NULL; pw = getpwuid (geteuid ()); if (pw) user = pw->pw_name; else if ((user = getenv ("USER")) == NULL) {
fprintf (stderr, "I don't know!\n"); return 1; } printf ("%s\n", user); return 0; } int main (int argc, char **argv) { if (argc > 1) { fprintf (stderr, "usage: whoami\n"); return 1; } return who_am_i (); } 运行 cflow 产生下面的输出: $ cflow whoami.c main() : fprintf() who_am_i() : getpwuid() geteuid() getenv() fprintf() printf() 这是一个正向调用图显示了输入文件中的调用者-被调用者依赖关系。每一行以 一个函数名开始,紧跟后面有一对括号来指明这是一个函数。如果这个函数在某 一个输入文件中定义,这一行会使用一对尖括号,其中显示函数的原型和它被定 义的位置。这一行将会以:结尾来表示这个函数调用了其它函数。比如,这一行 main() : 显示 main 函数在源文件 whoami.c 中的第 25 行定义,原型是 int main (int argc,char **argv),最后的冒号表示 main 函数调用了其他函数。 这一行后面的是被 main 函数调用的函数。每一行都会根据嵌套关系有相应的缩 进。
通常 cflow 会显示完整的函数原型。然而有时你希望忽略原型的一部分。一些选 项可以用来完成这个功能。使用--omit-symbol-names 选项来打印没有函数名的原 型。使用--omit-arguments 选项来忽略参数列表。这些选项可以被用做很多用途, 其中一个就是使结果图更加的紧凑。为了显示他们的作用,下面是使用上述两种 --omit-选项的结果:main() : 默认情况下,cflow 从 main()函数开始输出正向图。当分析一个完整的 C 程序集 的时候这是非常的便利的。但是有时候用户可能只想看到从特定函数出发的部分 图。使用—main(-m)选项,Cflow 允许选择这样的功能调用。因此,运行$cflow --main who_am_i whoami.c,将会得到下面的结果: who_am_i() : getpwuid() geteuid() getenv() fprintf() printf() 3、两种类型的流图 在前面我们讨论了正向图,用于展示调用者-被调用者的依赖关系。另一种 cflow 输出是逆向图,列举被调用者-调用者的依赖关系。,为了生成逆向图,运行 cflow 的时候要使用--reverse(-r)选项。比如使用下面的例子: $ cflow --reverse whoami.c fprintf(): who_am_i() : main() main() getenv(): who_am_i() : main() geteuid(): who_am_i() :
main() getpwuid(): who_am_i() : main() main() printf(): who_am_i() : main() who_am_i() : main() 这个输出包含了几个子图,每一个字图描述了一个特定的函数的调用者。因此, 第一个子图说明函数 fprintf 被两个函数调用:who_am_i 和 main。同时他也被 main 函数直接调用。 第一个值得注意的地方是在输出中 who_am_i 重复出现了多次。这是一个详细的 输出,为了让输出显得更加简洁,可以使用--brief(-b)选项。比如: $ cflow --brief --reverse whoami.c fprintf(): who_am_i() : main() main() [see 3] getenv(): who_am_i() : [see 2] geteuid(): who_am_i() : [see 2] getpwuid(): who_am_i() : [see 2] main() [see 3] printf(): who_am_i() : [see 2] who_am_i() : [see 2] 在简要输出中,一旦某个给定的函数被写入,随后的关于该函数的调用实例中将 会只包含它的定义和第一次输出行的引用。 如果输出图比较大,查找需要的行数就会比较麻烦(除非你使用 Emacs 的 cflow-mode)。这种情况下可以使用特殊的选项--number (-n),这样就可以在输出 时显示每一行的顺序标号。使用这个选项,上面的输出将变成这样:
$ cflow --number --brief --reverse whoami.c 1 fprintf(): 2 who_am_i() : 3 main() 4 main() [see 3] 5 getenv(): 6 who_am_i() : [see 2] 7 geteuid(): 8 who_am_i() : [see 2] 9 getpwuid(): 10 who_am_i() : [see 2] 11 main() [see 3] 12 printf(): 13 who_am_i() : [see 2] 14 who_am_i() : [see 2] 当然,--brief 和--number 选项对正向图和逆向图都起作用。 4、各种输出格式 前面所描述的输出格式被称为 GNU 类型。除此之外,cflow 也可以使用 POSIX 产 生格式化的输出。这种格式,输出的每一行都以一个参考数字开始,比如,最开 始是输出行的顺序号,后面跟随每一个嵌套层的固定长度的缩进。然后如果有的 话依次是函数的名字、冒号、函数的原型。紧跟在函数原型后面的是定义的位置 (包括文件名和行号)。函数顶一个位置都被尖括号围住。如果函数的定义没有 找到,该行将会以一个空的尖括号结尾。 使用格式化输出要么在命令行中通过--format=posix (-f posix)选项指定,要么设置 环境变量 POSIXLY_CORRECT 。 使用 POSIX 格式处理我们的样例文件,如下: $ cflow --format=posix whoami.c 1 main: int (int argc,char **argv), 2 fprintf: <> 3 who_am_i: int (void), 4 getpwuid: <>
5 geteuid: <> 6 getenv: <> 7 fprintf: <> 8 printf: <> 是否在输出中要包含函数的参数列表现在并不清楚。默认情况下 cflow 将会全部 打印它们。然而一些程序使用 cflow 分析时希望省略参数列表,这可以使用 --omit-arguments 选项实现。 cflow 未来的版本中将会提供更多的输出格式,包括 XML 和 HTML 输出。目前你 可以使用 VCG 工具来创建典型的图。根据 xvcg 来转变输出格式可以使用 cflow2vcg 程序在 GPL 下都是可用的。 Cflow2vcg 期望使用 POSIX 格式图,每层嵌套的缩进为一个水平制表符,第 0 层 使用额外的 tab 字符,在函数声明中没有参数列表。这样用可兼容 cflow2vcg 产 生的输出格式,调用 cflow 如下: cflow --format=posix --omit-arguments \ --level-indent='0=\t' --level-indent='1=\t' \ --level-indent=start='\t' 你可以使用下面的脚本来虚拟调用这三个工具: #! /bin/sh cflow --format=posix --omit-arguments \ --level-indent='0=\t' --level-indent='1=\t' \ --level-indent=start='\t' $* | cflow2vcg | xvcg - 5、处理递归调用 有时候程序中包含调用自己的函数。GNU 输出格式为这种函数提供了特殊的表 示。在结束字符-冒号之前,会有一个标号‘(R)’作为递归函数的标志。随后递 归调用处会在行结尾使用‘(recursive: see refline)’标识出。这里的 refline 表示递
分享到:
收藏