之前使用Graphviz生成了一张mongoose的函数调用图,这里将讲是怎么生成的。
通过Graphvis生成mongoose的函数调用关系
基本的理论可以参考这里(http://www.ibm.com/developerworks/cn/linux/l-graphvis/), 思路如下:
1. 通过GCC的 -finstrument-functions 和 -g 选项,获得函数调用关系的地址.
2. 使用 Addr2line 将函数地址解析为函数名.
3. 精简函数跟踪数据(可以参考pvtrace, http://download.boulder.ibm.com/ibmdl/pub/software/dw/library/l-graphvis/pvtrace.zip)
4. 使用Graphvis生成图片.
具体的步骤:
1. 在我们编译mongoose的时候,加上 instrument.c 文件。
instrument.c 文件的作用是在我们执行文件的时候,会自动记录函数入口和出口的函数地址,并保存在当前目录下面的trace.txt文件里面。 注意: 在用gcc编译的时候一定要加 -finstrument-functions 和 -g 参数。
在mongoose的Makefile文件中增加instrument.c文件。
原文:
$(CC) $(LINFLAGS) mongoose.c main.c -s -o $(PROG)
改为:
$(CC) $(LINFLAGS) instrument.c mongoose.c main.c -finstrument-functions -g -s -o $(PROG)
2. 编译mongoose.
make linux
3. 运行编译好的mongoose程序,并在当前目录生成一个trace.txt 文件。
3. 下载 pvtrace.zip 并编译。
回生成一个pvtrace程序,这个程序主要是从trace.txt和mongoose中提取函数地址对应的函数名,并生成graphivz的语法树。
4. 使用你编译好的文件pvtrace, 运行mongoose, 来获得graph.dot文件。
5. 使用Graph程序,生成图片, 前提是你必须安装graphivz
Debian/Ubuntu
sudo apt-get install graphviz.
安装完后运行:
dot -Tjpg graph.dot -o graph.jpg
6. Over.
效果图参考: http://wifihack.net/blog/2009/04/mongoose-start-function-call-use-graph/
instrument.c:
/********************************************************************
* File: instrument.c
*
* Instrumentation source — link this with your application, and
* then execute to build trace data file (trace.txt).
*
* Author: M. Tim Jones <mtj@mtjones.com>
*
*/
#include <stdio.h>
#include <stdlib.h>
/* Function prototypes with attributes */
void main_constructor( void )
__attribute__ ((no_instrument_function, constructor));
void main_destructor( void )
__attribute__ ((no_instrument_function, destructor));
void __cyg_profile_func_enter( void *, void * )
__attribute__ ((no_instrument_function));
void __cyg_profile_func_exit( void *, void * )
__attribute__ ((no_instrument_function));
static FILE *fp;
void main_constructor( void )
{
fp = fopen( “trace.txt”, “w” );
if (fp == NULL) exit(-1);
}
void main_deconstructor( void )
{
fclose( fp );
}
void __cyg_profile_func_enter( void *this, void *callsite )
{
fprintf(fp, “E%p\n”, (int *)this);
}
void __cyg_profile_func_exit( void *this, void *callsite )
{
fprintf(fp, “X%p\n”, (int *)this);
}
Ref:
1. 用 Graphviz 可视化函数调用 http://www.ibm.com/developerworks/cn/linux/l-graphvis/
–EOF–
Recent Comments