这些信息是 ubuntu 7.10 , gcc 4.1.3, gdb 6.6-debian 跟踪的
当printf不够有效时。。。。
1。读懂错误信息
一个简单的例子;
#include <stdio.h>
#include <stdlib.h>
void a(){
char *s = "ee";
free(s);
}
int main(int argc, char **argv){
a();
return 1;
}
程序运行可以得到一下错误信息:
*** glibc detected *** ./r: free(): invalid pointer: 0x0804865c ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xb7e2dd65]
/lib/tls/i686/cmov/libc.so.6(cfree+0x90)[0xb7e31800]
./r[0x804838c]
./r[0x80483a4]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0xb7dda050]
./r[0x8048311]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:05 1047431 /home/jing/Desktop/ee/r
08049000-0804a000 rw-p 00000000 08:05 1047431 /home/jing/Desktop/ee/r
0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
b7db8000-b7dc2000 r-xp 00000000 08:05 3499334 /lib/libgcc_s.so.1
b7dc2000-b7dc3000 rw-p 0000a000 08:05 3499334 /lib/libgcc_s.so.1
b7dc3000-b7dc4000 rw-p b7dc3000 00:00 0
b7dc4000-b7f08000 r-xp 00000000 08:05 3532035 /lib/tls/i686/cmov/libc-2.6.1.so
b7f08000-b7f09000 r--p 00143000 08:05 3532035 /lib/tls/i686/cmov/libc-2.6.1.so
b7f09000-b7f0b000 rw-p 00144000 08:05 3532035 /lib/tls/i686/cmov/libc-2.6.1.so
b7f0b000-b7f0e000 rw-p b7f0b000 00:00 0
b7f22000-b7f24000 rw-p b7f22000 00:00 0
b7f24000-b7f3e000 r-xp 00000000 08:05 3499469 /lib/ld-2.6.1.so
b7f3e000-b7f40000 rw-p 00019000 08:05 3499469 /lib/ld-2.6.1.so
bff2d000-bff42000 rw-p bff2d000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
Aborted (core dumped)
backtrace 提供函数的调用情况。
memroy map 是程序分配是虚拟内存的分配情况, 它的格式在各个操作系统下是不同的。 以上信息是linux下的运行。实际上输出的是/proc/pid/maps的信息。
(这个图在我的浏览器下显示不正常,可以点击memory map的连接查看源)
40049000-4035c000 r-xp 00000000 03:05 824473 /jdk1.5/jre/lib/i386/client/libjvm.so |<------------->| ^ ^ ^ ^ |<----------------------------------->| Memory region | | | | | | | | | | Permission --- + | | | | r: read | | | | w: write | | | | x: execute | | | | p: private | | | | s: share | | | | | | | | File offset ----------+ | | | | | | Major ID and minor ID of -------+ | | the device where the file | | is located (i.e. /dev/hda5) | | | | inode number ------------------------+ | | File name -------------------------------------------------------+
代码段(code segement)的权限是r-xp, 数据段(data segment)是rw-p
如果能马上明白错在哪里就好了, 如果不能马上找出错误, 就需要一些技巧快速找到问题的所在。
2. 找出出错的函数
链接程序时用到 -rdynamic 选项
gcc -g -o memleak memleak.c -rdynamic -ldl
-rdynamic
dlopen
-ldl 可以查看man dlopen (我不怎么明白这个dynamic linking 的实质.)
运行, 报错, 可以得到带符号表的信息:
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xb7dfed65]
/lib/tls/i686/cmov/libc.so.6(cfree+0x90)[0xb7e02800]
./r(a+0x18)[0x804859c]
./r(main+0x16)[0x80485b4]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0xb7dab050]
从这里可以看出, a()的 free()调用错误了。
3. stack trace定位错误到行
如果一个函数被多次调用, 函数名就不足以区分到底是哪个调用出问题了。下面的方法可以试一下:
- 调用gdb调试
- 设置对出错函数的断点, 比如b free
- 到达断点后, 命令: bt, 查看函数调用情况, 就可以找出是哪个函数被调用, 直到找到出错的调用
* 把每一个函数检查一遍是很麻烦的, 可以捕捉系统发出的错误信号,
























调试的时候, b sighandler, 然后bt.
但捕捉sigsegv是危险的,不能无限的捕捉, 不然无限循环了。捕捉一次就够。
5. 或者gdb下,在程序被强制退出后, 试一下list命令
6。工具:valgrind
内存差错的工具很多,valgrind是最强大的一个。有些工具提供一个库,连接到源代码,完了还要改回去,不方便。
有些工具检查一些特定的调用:
* strace: 系统调用, 比如文件打开,关闭
* mtrace, electronice fence(电网), dmalloc, MEMWATCH(mastering linux debugging techniques): malloc调用
* ltrace: "dynamic library call"
* nm, objdump: obj文件信息,信息太繁琐了, 也许要不得以而用之。 没有用过这两个工具。
7。其它