在linux上,程序运行崩溃,通过dmesg,我们经常可以看到如下的崩溃信息。
[30573389.794159] a.out[8535]: segfault at 0 ip 00007f038f8e15b6 sp 00007ffcab34e670 error 4 in libread.so[7f038f8e1000+1000]
那么通过该信息,怎样定位到崩溃位置的函数和行号呢?
信息简述
- at 0 变量内容
- ip 00007f038f8e15b6 指令地址
- sp 00007ffcab34e670 栈顶地址
- error 4 错误类型
- 崩溃的库
- [7f038f8e1000+1000] 7f038f8e1000是库在内存映射中的 基地址,+1000不知道是啥
错误类型 的定义如下
* Page fault error code bits:
*
* bit 0 == 0: no page found1: protection fault
* bit 1 == 0: read access1: write access
* bit 2 == 0: kernel-mode access1: user-mode access
* bit 3 == 1: use of reserved bit detected
* bit 4 == 1: fault was an instruction fetch
实例
(动态库cpp文件)
int get_num_by_ptr(int *ptr)
{
return *ptr;
}
void set_num_by_ptr(int *ptr, int num)
{
num = *ptr;
}
(主文件)
extern int get_num_by_ptr(int *ptr);
int main(void)
{
int num = get_num_by_ptr(0); //空指针解引用
return 0;
}
- 编译运行
gcc read.c -g -fPIC -shared -o libread.so //没有-g,看不到行号,只能看到函数名
gcc main.c -L. -lread
./a.out
Segmentation fault (core dumped)
dmesg | tail -n1
[30573389.794159] a.out[8535]: segfault at 0 ip 00007f038f8e15b6 sp 00007ffcab34e670 error 4 in libread.so[7f038f8e1000+1000]
- 分析
由崩溃信息得到,崩溃时的指令地址为0x7f038f8e15b6,在内存映射中的基地址为0x7f038f8e1000,那么崩溃地址在中的相对偏移地址为5b6 = 7f038f8e15b6 - 7f038f8e1000。
用addr2line调试可得(addr2line需要的是偏移地址)
addr2line -f -C -e libread.so 5b6
get_num_by_ptr
/root/seg/read.c:3
- 总结
段错误,简单来说就是内存访问错误。大致分为这几类:
- 访问不存在或未分配的内存地址。
nullptr就属于不存在的内存地址,被释放的内存或未分配的内存就属于未分配的内存地址。
- 访问没有权限的内存地址。
如访问内核空间地址,对只读内存地址进行写操作(改变const修饰的变量)。