前言

本文章旨在作为笔记,温故而知新,也希望能帮到各位有需要的道友,若有任何建议或探讨可加 QQ群进行交流:887939177

目的

在linux实际项目中(即程序已上线),会遇到程序无缘无故崩溃的现象,此时常规日志可能无法分析出故障原因。
本文介绍两种方式,方式一为系统生成core文件模式,方式二程序监听崩溃信号并打印堆栈信息。

推荐使用方式二,(方式一会根据程序内存使用大小会影响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)进行讨论!
QQ群二维码

Logo

更多推荐