2007年5月15日星期二

用CodeViz绘制函数调用关系图

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 安装

分别下载和按这个顺序安装如下软件
1. graphviz 2.2.1
http://www.graphviz.org/pub/graphviz/ARCHIVE/graphviz-2.2.1.tar.gz
现在最新的是2.12了,但是make install是错现错误,另外,最新版并没有太大的update,所以 还是选用这个版本。
安装: 1. 解压该文件后运行./configure
2. make; make install

2. codeviz-1.0.11.tar.gz
http://www.csn.ul.ie/~mel/projects/codeviz/codeviz-1.0.11.tar.gz
安装: 1. 解压该文件后运行./configure
2. make; make install

使用CodeViz的正确步骤是:
(1)指定make CC=/usr/local/gccgraph/bin/gcc CXX=/usr/local/gccgraph/bin/g++ (好象也不用)

(2)想办法让 gcc 能编译内核源代码或范例程序的源码,每个C源文件生成对于的.c.cdepn文件。只要编译(参数 -c)就行,无需连接。
例如:/usr/local/gccgraph/bin/gcc -c ok.c 此时产生了两个文件ok.c和ok.c.cdepn
如果想编译内核Linux-2.6.17,可以这样做:
tar xjvf linux-2.6.17.tar.bz2
cd linux-2.6.17
make menuconfig
make dep (对2.6以上的内核次步就不用了) #生成依赖性
make bzImage (注意:这需要5-10分钟) #产生压缩内核
make modules ( #编译可加载模块)

(3)先产生full.graph文件,例如:
genfull -s "include/linux net/ipv4"
genfull -s "mm include/linux drivers/block arch/i386"

(4)根据产生出来的full.graph来生成我们感兴趣的函数调用图,例如:
gengraph -f ip_rcv
gengraph -f alloc_pages
注意:gengraph -f alloc_pages但这会产生一个非常复杂的ps文件,以致一张ps文件都显示不下。但可以这样处理
gengraph --output-type gif -t -d 10 -s "shrink_cache try_to_free_pages_zone" -i "__free_pages_ok" -f alloc_pages


2007年5月14日星期一

Wine 安装

1. 在http://www.winehq.org/上下载最新的source code, 如:
http://prdownloads.sourceforge.net/wine/wine-0.9.37.tar.bz2

2. 使用非root用户解压wine-0.9.37.tar.bz2
3. 使用tools/wineinstall编译安装Wine
4. 如果要使root能够运行 Wine, 请将/home/(安装用户名)/.wine 拷贝到/root下