一段测试代码发生非法内存访问,发生段错误收到 SIGSEGV 信号崩溃,通过如下几种方法快速的定位到崩溃前的调用栈。
1、借助 valgrind 工具。
valgrind ./test.out
可看到 test.cpp 203 行调用了 std::string 的empty 函数,导致的奔溃。
0x401E2B 是函数 CDropScopeConfig::initLineContext 的地址。
可通过 addr2line 查看。
addr2line -e test.out 0x401E2B -f
C++ name magling 之后的名称,可通过 c++filt 还原。
2、使用 dmesg 查看内核记录的错误信息快速的定位崩溃的地方。
非法访问 0xffffffffffffffe8 地址。
地址 00000030548bc413 和源码中函数的地址差异比较大,因为这个地址的函数来自动态连接库 .so 文件中。通过 ldd 查看当前程序所动态连接的库文件,发现该地址在 /usr/lib64/libstdc++.so.6 文件的范围内,同样使用 add2line 工具,定位到具体的函数。
3、通过 core 文件快速的定位。
通过 ulimit 查看core 文件的大小配置,如果为0表示不产生 core 文件。ulimit -c unlimited 设置不限制大小。
查看 /proc/sys/kernel/core_pattern 文件,查看 core 文件生成的位置。
gdb test.out core文件
使用 where 打印调用栈。
如果行号显示不全,推荐使用新版本的 gdb。
4、其他的 GNU 的工具集 binutils 定位。
使用 objdump 定位到对应的汇编:
objdump -d /usr/lib64/libstdc++.so.6 | grep 30548bc413
objdump 得到的汇编代码定位到的位置: