在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 错误类型
  • libread.so 崩溃的库
  • [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

实例

read.c (动态库cpp文件)

int get_num_by_ptr(int *ptr)
{
	return *ptr;
}

void set_num_by_ptr(int *ptr, int num)
{
	num = *ptr;
}

main.c (主文件)

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,libread.so在内存映射中的基地址为0x7f038f8e1000,那么崩溃地址在libread.so中的相对偏移地址为5b6 = 7f038f8e15b6 - 7f038f8e1000。
用addr2line调试可得(addr2line需要的是偏移地址)

addr2line -f -C -e libread.so 5b6
get_num_by_ptr
/root/seg/read.c:3
  • 总结

段错误,简单来说就是内存访问错误。大致分为这几类:

  • 访问不存在或未分配的内存地址。

nullptr就属于不存在的内存地址,被释放的内存或未分配的内存就属于未分配的内存地址。

  • 访问没有权限的内存地址。

如访问内核空间地址,对只读内存地址进行写操作(改变const修饰的变量)。

Logo

鸿蒙生态一站式服务平台。

更多推荐