broadcom63283环境使用dmalloc调试内存泄露

一、生成dmalloc静态库

1、从网上下载dmalloc源码,修改configure文件中的ac_cv_page_size=012,否则会出现在交叉编译环境下configure执行不通过

echo $ECHO_N "checking basic-block size... $ECHO_C" >&6

ac_cv_page_size=0

2、使用交叉编译环境执行configure

[liujianfeng@bcm-server dmalloc-5.5.2]$./configure --target=mips-linux-uclibc --host=mips-linux-uclibc CC=/opt/toolchains/uclibc-crosstools-gcc-4.4.2-1/usr/bin/mips-linux-uclibc-gcc CXX=/opt/toolchains/uclibc-crosstools-gcc-4.4.2-1/usr/bin/mips-linux-uclibc-g++

3、修改return.h文件,增加MIPS体系的GET_RET_ADDR内联汇编功能宏代码,在后面查看统计信息时,该值就是内存泄露点的详细地址,根据此地址在结合GDB工具可以方便查到是哪个文件哪行出现的内存泄露。(备注:当前作者使用的bcm板子是MIPS处理器,如果其它处理器体系请参考其它处理器获取函数返回地址的汇编代码)。

/* LIUJF FOR BCM MIPS */

#define GET_RET_ADDR(file) { asm volatile ("sw $ra, %0" : "=m" (file)); }

 

/* for all others, do nothing */

#ifndef GET_RET_ADDR

#ifdef DMALLOC_DEFAULT_FILE

4、编译线程可重入版本的静态库。编译完成后会在当前目录下生成libdmallocth.a静态库,

libdmallocth.aC版本静态库,如果要编译支持C++版本的静态库使用make threadscxx

[liujianfeng@bcm-server dmalloc-5.5.2]$make threads

 

二、生成调试程序(将需要调试内存泄露的程序代码与dmalloc静态库一同编译,生成含内存泄露调试信息的用户程序)

1、修改需要调试的应用程序代码,加入SIGINT信号处理函数,在该信号处理函数中加入dmalloc_shutdown()调用,这样当我们使用Ctrl+C终止应用程序时,dmalloc就会在程序退出时进行信息统计,详见如下参考代码bcm_dmalloc_test.c

提示:

如果应用程序是不可退出的,也可以在程序运行中查看统计信息,dmalloc提供了打标记及查看此标记之后日志变更的接口函数,这样就可以在应用程序的命令行中加入两个命令接口,分别调用dmalloc的两个接口函数。

unsigned long mark = dmalloc_mark();

dmalloc_log_changed(mark, 1, 0, 1);

2、将要调试的程序代码与libdmallocth.a静态库一起编译,生成我们需要的调试版本程序,这里一定要注意libdmallocth.a放在编译依赖的最后面,因为放在前面dmalloc调试功能就不启作用了,dmalloc的实现原理主要是在编译时使得应用程序的内存操作(如malloc)调用dmalloc库中的malloc接口,然后dmalloc的malloc函数调用系统的brk进行内存申请,从而使用dmalloc库接管的应用程序的内存操作而可以进行统计分析,详见dmalloc的源码。

[liujianfeng@bcm-server test]$/opt/toolchains/uclibc-crosstools-gcc-4.4.2-1/usr/bin/mips-linux-uclibc-gcc -o dmalloc_test bcm_dmalloc_test.c libdmallocth.a -lpthread

三、板子上进行程序调试

1、将交叉编译好的调试程序dmalloc_test上传到板子上,并在板子上设置环境变量(手工设置输入下面2行命令,我这里仅仅是测试,如果其它同事需要在工作项目使用,可以将环境变量直接写到板子/etc/profile文件中)。这步必须要操作,否则没有统计信息输出。

DMALLOC_OPTIONS="debug=0x4000503,log=/var/bcm_dmalloc.log"

export DMALLOC_OPTIONS

提示:

也可以不设置环境变量,直接调用dmalloc的接口函数来设置相关参数

dmalloc_debug_setup("debug=0x4000503,log=/var/bcm_dmalloc.log ");

2、运行板子上的dmalloc_test测试程序,在这个测试程序中我固意加了一些内存泄露的代码,在准备查看当前是否存在内存泄露信息时,按Ctrl+C中止当前测试程序。(目前我在63283的天翼猫环境,一按Ctrl+C就卡住了,我没有去找原因,仅仅提前用telenet先登陆,如果串口卡住,就直接用telenet把卡住的这个测试程序杀死)。

此时查看/var目录下生成了一个bcm_dmalloc.log文件,该文件格式比较容易看懂。

其中我们最关心的是像“not freed: '0x496fe8|s1' (10 bytes) from 'ra=0x40163c'”格式的这些行,这条记录表示0x496fe8内存指针没有释放,该内存大小为10个字节,其中ra=0x40163c”就是内存泄露的代码地址处。这个地址需要编译出带调试信息的版本,然后借助GDB工具就可以很清楚的知道ra=0x40163c是表示当前代码的哪个文件、哪行。

 

例如我当前重新编译一个含调试信息的版本

[liujianfeng@bcm-server test]$ /opt/toolchains/uclibc-crosstools-gcc-4.4.2-1/usr/bin/mips-linux-uclibc-gcc -o dmalloc_test_dbg -g bcm_dmalloc_test.c libdmallocth.a -lpthread

 

然后使用gdblist命令查看那个引起内存泄露的代码地址,从下面打印信息我们可以很清楚的看到当前内存泄露点出现在 bcm_dmalloc_test.c文件的32行代码处,char *p = (char *)malloc(10);

 

/opt/toolchains/uclibc-crosstools-gcc-4.4.2-1/usr/bin/mips-linux-uclibc-gdb dmalloc_test_dbg

(gdb) list *(0x40163c)

0x40163c is in test_thread_1 (bcm_dmalloc_test.c:32).

27

28      void test_thread_1( void )

29      {

30              while ( 1 )

31              {

32                      char *p = (char *)malloc(10);

 

四、提示

dmalloc支持两种使用方式。

一种是调试程序只进行dmalloc静态库的编译链接(上面介绍的就是这种方式),这种方式的好处是对于代码量比较大的现有程序,无需要关心每个.c文件的编译细节,只需要将dmalloc静态库放在程序依赖的最后面即可。但缺点是针对不同CPU体系需要了解基本的函数返回地址汇编实现,同时即使得到了泄露源的地址变量,但也需要借助gdbobjdumpmap文件等手段得到该泄露源的真正文件/行号或函数范围。

 

还有一种方式除了使用dmalloc静态库编译链接外,还需要在每个要调试的.c程序文件中加入dmalloc.h文件的引用,这种方式的原理是使用dmalloc.h头文件的宏定义将需要调试的.c程序文件中的malloc替换为dmalloc_malloc,这种方式的好处和上面方式正好相反,不需要了解不同CPU体系的汇编,不需要借助gdb等工具,因为编译宏的替换可以直接使用__FILE____LINE__宏,所以得到的调试信息直接是可以看到的文件名/行号。但缺点也很明显,需要保证所有需要调试的.c程序文件,都要引用了dmalloc.h头文件。

你可能感兴趣的:(DEBUG)