gdb:gcc调试工具,用于C和G++编写的程序。
gdb调试先决条件:想将调试信息加到可执行文件中。
gcc -g hello.c -o hello
g++ -g hello.cpp -o hello
没有-g,将看不见程序的函数名和变量名,以内存地址代替。
gdb启动方法:
- gdb program(执行文件)
- gdb program core
同时调试一个运行程序和core文件(core dump)。 - gdb program 1234
当程序是一个服务程序,可以指定这个服务程序运行时的进程ID,gdb会自动进行attch,并调试这个程序。
gdb常用语法:
- l : 列出函数代码及其行数。
- b 16 : 在代码16行处设置断点。
- b func:在函数func处设置断点。
- r:运行程序。
- n : 单挑执行语句。
- p i : 打印i变量。
- finish : 退出函数。
- q : 结束调试。
用gdb分析coredump文件 :
core,又称之为coredump,是UNIX/linux操作系统的一种机制。
OS在coredump的同时,虽然会终止当前进程,但是也会保留第一手的现场数据。
coredump文件含有当进程被终止时内存,CPU寄存器和各种函数调用堆栈信息等。
-
coredump文件的存储路径
可以通过以下命令看到core文件的存在位置:cat /proc/sys/kernel/core_pattern
通过以下命令可以更改coredump的存储位置:
echo "/data/coredump/core.%e.%p" >/proc/sys/kernel/core_pattern
这样配置后,产生的core文件带有崩溃的程序名以及进程ID。
-
有时候程序coredump了却没有产生coredump
1 ) 确认当前会话能生成的coredump文件大小,可以通过ulimit -c查看coredump文件的大小值,如果为0则不会产生core文件。可以通过以下命令修改:ulimit -c unlimited
但当前设置的ulimit只对当前会话有效,要想系统均有效,则需 要如下配置:
vim /etc/profile ulimit -c unlimited
2 ) 保证当前用户对写入core的目录有写权限和足够空间。
-
产生coredump文件的原因
1 ) 内存访问越界
数组下标,字符串结束符,字符串操作函数等。
2 ) 多线程程序使用了线程不安全的函数。
3 ) 多线程读写的数据未加锁保护。
4 ) 非法指针,包括使用空指针或随意使用指针转换。
5 ) 堆栈溢出,不要使用大的局部变量(分配在栈上)。
gdb定位coredump文件
用以下一个例子:
#include<stdio.h>
int main()
{
int b=1;
int *a;
*a =b;
return 0;
}
编译后执行./test1命令,结果如下图:
将core文件从自定义的目录复制到当前目录之下
cp core.test1.2724 /opt/test/gdb
先来看该core文件的ELF头部
readelf -h core.test1.2724
可以观察到类型是core文件。
接下来使用gdb,先从可执行文件中读取符号表信息,然后读取core文件。如果不与可执行文件一起操作,则无法进行调试,可以用如下命令验证:
objdump -x core.test1.2724 | tail
可以发现符号表里并没有信息。
那么接下来查看core的位置:
gdb test1 core.test1.2724
结果显示在第6行,*a=b处,分别打印变量a和b的值:
发现a变量指向非法区域,也就是因为a没有分配内存导致。