本文章旨在作为笔记,温故而知新,也希望能帮到各位有需要的道友,若有任何建议或探讨可加 QQ群进行交流:887939177
在linux实际项目中(即程序已上线),会遇到程序无缘无故崩溃的现象,此时常规日志可能无法分析出故障原因。
本文介绍两种方式,方式一为系统生成core文件模式,方式二程序监听崩溃信号并打印堆栈信息。
推荐使用方式二,(方式一会根据程序内存使用大小会影响core文件大小,若程序内存开销很大会造成core文件很大,在写文件时会影响系统性能)
1.首先输入命令: ulimit -c,如果返回0,说明当前没有开启自动保存崩溃文件功能,可通过以下命令开启并设置文件大小限制(unlimited代表不限制,若需限制可写具体数值)。
ulimit -c unlimited
2.设置崩溃文件保存路径(需保证文件夹存在),命令如下,
echo "/var/core/core-%e-%p-%t-%s.err" > /proc/sys/kernel/core_pattern
至此配置完成,当程序崩溃时系统自动将信息写入指定的文件夹并按规则命名。
3.打印崩溃日志,命令如下,
gdb -c /var/core/[生成的core文件名] [可执行文件]
gdb -c /var/core/core-test-18829-1549201876-11.err ./test
执行上述命令后,会进入gdb调试模式,然后输入命令:bt,便会打印崩溃堆栈。
1.在程序中添加进程信号监听,例如:
signal(SIGSEGV, sigHandler);
signal(SIGABRT, sigHandler);
2.实现绑定函数sigHandler,如下:
void sigHandler(int signo)
{
LOG_ERROR_ARGS("=====recv SIGINT %d=====", signo);
//打印错误堆栈信息
LOG_ERROR("----------------------------Dump Program Error Strings-------------------------");
int j = 0, nptrs = 0;
void* buffer[100] = { NULL };
char** strings = NULL;
nptrs = backtrace(buffer, 100);
LOG_ERROR_ARGS("backtrace() returned %d addresses", nptrs);
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
LOG_ERROR("backtrace_symbols null");
LOG_ERROR("-------------------------------------------------------------------------------");
return;
}
for (j = 0; j < nptrs; j++) {
LOG_ERROR_ARGS(" [%02d] %s", j, strings[j]);
}
free(strings);
LOG_ERROR("-------------------------------------------------------------------------------");
//恢复默认信号操作
signal(signo, SIG_DFL);
raise(signo);
}
以上主要利用backtrace及backtrace_symbols来获取程序崩溃时的堆栈信息,后续就是以此信息来查找程序具体执行到哪一步崩溃的。
3.编译程序时请添加 -g -rdynamic 的编译选项,
gcc -g -rdynamic -o test test.c
3.打印信息大致如下:
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : =====recv SIGINT 11=====
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : RsuGasStation.cpp[14] ----------------------------Dump Program Error Strings-------------------------
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : backtrace() returned 6 addresses
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : [00] ./rsu_gasstation(_Z23DumpProgramErrorStringsv+0x131) [0x559abf9059b7]
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : [01] ./rsu_gasstation(_Z10sigHandleri+0x113) [0x559abf905e95]
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : [02] /lib/x86_64-linux-gnu/libc.so.6(+0x3efd0) [0x7f67f5181fd0]
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : [03] ./rsu_gasstation(main+0x17d) [0x559abf906062]
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : [04] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f67f5164b97]
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : [05] ./rsu_gasstation(_start+0x2a) [0x559abf8f9d1a]
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : RsuGasStation.cpp[32] -------------------------------------------------------------------------------
4.利用nm命令生成函数映射地址列表文件,命令如下:
nm -n [可执行文件] [生成的函数列表文件名]
nm -n test test.nm
5.在函数映射地址列表文件中查找错误信息中的对应函数,比如此行的main函数,
2020-07-15 16:54:34.669 [ERROR] 140084499824832 : [03] ./rsu_gasstation(main+0x17d) [0x559abf906062]
在文件中查找到的信息为:
0000000000027ee5 T main
6.此时可利用错误打印信息中的(main+0x17d),以及文件查找出来的地址,使用addr2line命令获取相关信息,如下:
addr2line -e [可执行文件] [地址:0x27ee5 + 0x17d]
addr2line -e test 0x28062
至此你便可看到具体信息,信息大致如下,可直观看到哪个函数哪一行,
sl@sl_rsu:~/projects/RsuGasStation/bin/x64/Debug$ addr2line -e rsu_gasstation 0x28062
/home/sl/projects/RsuGasStation/RsuGasStation.cpp:87 (discriminator 17)
sl@sl_rsu:~/projects/RsuGasStation/bin/x64/Debug$
signal信号参考网址:https://www.cnblogs.com/frisk/p/11602973.html
文章描述比较简单,希望能帮助到朋友们,如有疑问或建议,欢迎加QQ群(887939177)进行讨论!