运行环境:虚拟机下的Ubuntu 11.04

结合Graphviz工具,使用CodeViz可以生成直观和漂亮的C/C++程序函数之间的调用关系图。

1、安装graphviz

在安装CodeViz之前,必须先安装它所依赖的工具dot,否则将无法完成./configure操作并提示以下错误信息:

checking for dot...not found
FATAL: The program dot was not in your path. This is probably available for your distribution
with the graphviz package. Install this before running configure again

既可以从http://www.graphviz.org/Download_linux_ubuntu.php 上下载最新版本的graphviz安装程序手动安装,也可以使用以下命令自动安装:

$ sudo apt-get install graphviz graphviz-dev graphviz-doc

程序简要说明:

graphviz - rich set of graph drawing tools
graphviz-dev - transitional package for graphviz-dev rename
graphviz-doc - additional documentation for graphviz

安装相关库:

$ sudo apt-get install libgv-*

相关库简要说明:

libgv-guile - Guile bindings for graphviz
libgv-lua - Lua bindings for graphviz
libgv-ocaml - OCaml bindings for graphviz
libgv-perl - Perl bindings for graphviz
libgv-php5 - Php5 bindings for graphviz
libgv-python - Python bindings for graphviz
libgv-ruby - Ruby bindings for graphviz
libgv-tcl - Tcl bindings for graphviz

2、安装CodeViz

http://www.skynet.ie/~mel/projects/codeviz/ 上下载CodeViz安装包codeviz-1.0.10.tar.gz以及从ftp://ftp.gnu.org/pub/gnu/gcc/gcc-3.4.6 上下载GCC源码包gcc-3.4.6.tar.gz,并把它们拷贝到Ubuntu下的同一目录下。

然后解压CodeViz安装包,并把gcc-3.4.6.tar.gz拷贝到codeviz-1.0.10/compiler目录下:

$ tar zvxf codeviz-1.0.10.tar.gz
$ cd codeviz-1.0.10/
$ cp ../gcc-3.4.6.tar.gz compilers/ //也可以略过这一步,让ncftp(Ubuntu默认未安装)在make执行过程中自动下载gcc-3.4.6.tar.gz
$ ./configure

Patched GCC默认安装在/usr/local/gccgraph目录下。

  安装GCC时,需要安装下面的库

  apt-get install libgmp10-dev libmpfr-dev libmpc-dev

在执行make之前,先通过以下命令创建一个链接文件asm:

$ sudo ln -sf /usr/include/asm-generic/ /usr/include/asm

否则,在make执行过程中会出现在/usr/include/linux/errno.h文件中找不到asm/errno.h文件的错误信息并中止编译。

接下来执行make和make install命令即可在/usr/local/gccgraph目录下创建打过补丁的GCC编译器以及在/usr/local/bin目录下创建两个perl脚本程序genfull和gengraph。

$ make
$ sudo make install

3、CodeViz的使用举例

例子源代码如下:

/* test.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h> void func(char *p)
{
p = (char *)malloc(20);
} int main(void)
{
char *str = NULL; func(str); strcpy(str, "hello world"); printf("string is %s\n", str); return 0;
}

使用刚生成的编译器编译test.c,会相应地生成一个test.c.cdepn文件。

$ /usr/local/gccgraph/bin/gcc test.c

test.c.cdepn文件信息:

F {func} {test.c:6}
C {func} {test.c:7} {malloc}
F {main} {test.c:11}
C {main} {test.c:18} {printf}
C {main} {test.c:16} {strcpy}
C {main} {test.c:14} {func}

然后执行genfull脚本生成full.graph。

$ genfull

full.graph文件信息:

digraph fullgraph {
node [ fontname=Helvetica, fontsize=12 ];
"func" [label="func\ntest.c:5:"];
"main" [label="main\ntest.c:10:"];
"func" -> "malloc" [label="test.c:7"];
"main" -> "func" [label="test.c:14"];
"main" -> "strcpy" [label="test.c:16"];
"main" -> "printf" [label="test.c:18"];
}

最后执行gengraph生成函数关系调用图。

$ gengraph -f main --output-type "png"

-f指定最顶层的函数,--output-type指定图片的输出格式。

至于genfull和gengraph的详细使用说明请参考man手册,使用以下命令查看:

$ sudo apt-get install perl-doc //须先安装perl-doc
$ genfull --man
$ gengraph --man 另外参考:
http://blog.csdn.net/solstice/article/details/486788

CodeViz是《Understanding The Linux Virtual Memory Manager》(at Amazon下载地址在页尾)的作者 Mel Gorman 写的一款分析C/C++源代码中函数调用关系的open source工具(类似的open source软件有 egyptncc)。其基本原理是给 GCC 打个补丁,让它在编译时每个源文件时 dump 出其中函数的 call graph,然后用 Perl 脚本收集并整理调用关系,转交给Graphviz绘制图形。

CodeViz 原本是作者用来分析 Linux virtual memory 的源码时写的一个小工具,现在已经基本支持 C++ 语言,最新的 1.0.9 版能在 Windows + Cygwin 下顺利地编译使用:)。需要注意的是:1) 下载 GCC 3.4.1 的源码 gcc-3.4.1.tar.gz 放到 codeviz-1.0.9/compilers,2) 安装 patch 程序(属于Utils类),3) 从 http://www.graphviz.org 下载并安装 Graphviz 2.6。

我用 CodeViz 分析《嵌入式实时操作系统 uC/OS-II (第二版)》中的第一个范例程序,步骤如下:

1. 想办法让 gcc 能编译uC/OS 2.52和范例程序的源码,每个C源文件生成对于的.c.cdepn文件。只要编译(参数 -c)就行,无需连接。

2. 调用genfull生成full.graph,这个文件记录了所有函数在源码中的位置和它们之间的调用关系。

3. 使用gengraph生成我关心的函数的调用关系。

首先分析main():

1. gengraph --output-type gif -f main
分析main()的call graph,得到的图如下,看不出要领:

2. gengraph --output-type gif -f main -s OSInit
暂时不关心OSInit()的内部实现细节(参数 -s),让它显示为一个节点。得到的图如下,有点乱,不过好多了:

3. gengraph --output-type gif -f main -s OSInit -i "OSCPUSaveSR;OSCPURestoreSR"
基本上每个函数都会有进入/退出临界区的代码,忽略之(参数 -i)。得到的图如下,基本清楚了:

4. gengraph --output-type gif -f main -s "OSInit;OSSemCreate" -i "OSCPUSaveSR;OSCPURestoreSR" -k
OSSemCreate()的内部细节似乎也不用关心,不过保留中间文件sub.graph(参数 -k),得到的图如下,

5. dot -Tgif -o main.gif sub.graph
修改sub.graph,使图形符合函数调用顺序,最后得到的图如下,有了这个都不用看代码了:)

接着分析OSTimeDly()的被调用关系:

gengraph --output-type gif -r -f OSTimeDly

看看哪些函数调用了OSTimeDly(),参数 -r ,Task()和TaskStart()都是用户编写的函数:

最后看看Task()直接调用了哪些函数:

gengraph --output-type gif -d 1 -f Task

只看从Task出发的第一层调用(参数 -d 1):

在分析源码的时候,把这些图形打印在手边,在上面做笔记,实在方便得很。

[转] 使用CodeViz生成C/C++函数调用关系图的更多相关文章

  1. 利用graphviz软件和pycallgraph库自动生成Python代码函数调用关系图

    参考博文:https://blog.csdn.net/qq_36408085/article/details/82952846 https://blog.csdn.net/fondax/article ...

  2. 看开源代码利器—用Graphviz + CodeViz生成C/C++函数调用图(call graph)

    一.Graphviz + CodeViz简单介绍 CodeViz是<Understanding The Linux Virtual Memory Manager>的作者 Mel Gorma ...

  3. 用callgraph生成的函数调用关系图

    Wu Zhangjin 创作于 2015/04/05 评论打赏 By Falcon of TinyLab.org 2015/04/03 1 故事缘由 源码分析是程序员离不开的话题.无论是研究开源项目, ...

  4. 用callgraph生成的两张函数调用关系图

    参考这里,感觉很Cool吧. Linux-0.11函数调用关系图: QEMU函数调用关系图:

  5. 分析函数调用关系图(call graph)的几种方法

    绘制函数调用关系图对理解大型程序大有帮助.我想大家都有过一边读源码(并在头脑中维护一个调用栈),一边在纸上画函数调用关系,然后整理成图的经历.如果运气好一点,借助调试器的单步跟踪功能和call sta ...

  6. 用CodeViz绘制函数调用关系图(call graph)

    CodeViz是<Understanding The Linux Virtual Memory Manager>(at Amazon,下载地址在页尾)的作者 Mel Gorman 写的一款 ...

  7. c语言分析函数调用关系图(call graph)的几种方法

    一.基于 Doxygen或 lxr 的API形式的文档系统. 二.基于CodeViz, CodeViz是<Understanding The Linux Virtual Memory Manag ...

  8. python函数调用关系图(python call graph)

    由于要重构项目的部分代码,要整理好主要的函数调用关系,不想自己看代码慢慢画出结构,想找出一种通用的,节省人力的方法得出函数间的调用关系图,于是发现以下几个工具.(内网没装好graphviz,还没真正用 ...

  9. 使用egypt+graphviz生成函数调用关系图示例

    总结: make  (-fdump-rtl-expand)  去除编译优化,比如-O3 egypt test.c.128r.expand >test.dot  可以手动打开dot文件去除一些孤立 ...

随机推荐

  1. FC8下备份linux系统

    linux系统可以使用tar来备份.<br><br> 我在FC8上装好了totem, mplayer, audacious, 并搞定了wifi后,我觉得该备份一下FC8系统.& ...

  2. yii2 日志(log)的配置与使用

    原文地址: http://blog.csdn.net/gao_yu_long/article/details/51732181

  3. instancetype 与 id for Objective-C

    instancetype.id.NSObject的区别 - simalone   1.instancetype只能用于方法的返回类型,而id用处和NSObject *类似. 2.instancetyp ...

  4. 正则表达式:根据逗号解析CSV并忽略引号内的逗号

    需求:解析CSV文件并忽略引号内的逗号 解决方案: public static void main(String[] args) { String s = "a,b,c,\"1,0 ...

  5. Maven实战二

    简述: 现需要 在Eclipse中配置Maven插件 安装maven应用,配置Maven环境变量 建立Maven管理的工程 用Maven导入Gson包, 编写简易Json输出程序 步骤: 1. 首先到 ...

  6. mysql数据库操作语句大全

    一 . 常用mysql命令行命令 1 .启动MYSQL服务  net start mysql 停止MYSQL服务  net stop mysql 2 . netstat –na | findstr 3 ...

  7. Ehcache中配置详解

    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLoc ...

  8. bzoj3339 bzoj3585

    两题本质是一样,只不过3585要离散化这种不修改,不强制的问题,显然先考虑离线算法这道题的思路和bzoj1878非常像考虑到如果只是求每个前缀的mex,我们是很容易扫一遍就得出来的我们设为这个位置的m ...

  9. Linux Shell编程(5)——shell特殊字符(下)

    {}代码块[花括号]. 这个结构也是一组命令代码块,事实上,它是匿名的函数.然而与一个函数所不同的,在代码块里的变量仍然能被脚本后面的代码访问. bash$ { local a;      a=123 ...

  10. 树(最小乘积生成树,克鲁斯卡尔算法):BOI timeismoney

    The NetLine company wants to offer broadband internet to N towns. For this, it suffices to construct ...