linux應用程式除錯----backtrace
列印堆疊是除錯的常用方法,一般在系統異常時,我們可以將bai異常情況下的堆疊打印出來,這樣十分方便錯誤查詢。
先介紹下比較簡單的backtrace方式,後面有機會可以嘗試下core檔案+gdb的方式。
backtrace列印堆疊方式
編譯選項增加 -O0 -rdynamic -g -funwind-tables -ffunction-sections
CFLAGS ?= -mcpu=ck810 -static -mlittle-endian -Werror -O0 -rdynamic -g -funwind-tables -ffunction-sections
ASFLAGS += -O0
程式碼新增
#include <signal.h> /* for signal */ #include <execinfo.h> /* for backtrace() */ #define BACKTRACE_SIZE 32 void dump(void) { int j, nptrs; void *buffer[BACKTRACE_SIZE]; char **strings; printf("backtrace...\n"); nptrs = backtrace(buffer, BACKTRACE_SIZE); printf("backtrace() returned %d addresses\n", nptrs); strings = backtrace_symbols(buffer, nptrs); if (strings == NULL) { perror("backtrace_symbols"); exit(EXIT_FAILURE); } for (j = 0; j < nptrs; j++) printf(" [%02d] %s\n", j, strings[j]); free(strings); } void signal_handler(int signo) { #if 0 char buff[64] = {0x00}; sprintf(buff,"cat /proc/%d/maps", getpid()); system((const char*) buff); #endif printf("\n=========>>>catch signal %d <<<=========\n", signo); printf("Dump stack start...\n"); dump(); printf("Dump stack end...\n"); //exit(-1); signal(signo, SIG_DFL); /* 恢復訊號預設處理 */ raise(signo); /* 重新發送訊號 */ printf("app exit\n"); }
int main(void) { signal(SIGABRT, signal_handler); signal(SIGBUS, signal_handler); signal(SIGSEGV, signal_handler); }
執行結果:
=========>>>catch signal 11 <<<=========
Dump stack start...
backtrace...
backtrace() returned 7 addresses
[00] ./app-demo() [0xbf6e] // 最後一條指令
[01] ./app-demo() [0xc086] // 倒數第2調指令
[02] [0x2aac6000]
[03] /lib/libc.so.6(memcpy+0x30) [0x2ab516a0]
[04] ./app-demo() [0xbb62] // 出問題的地方
[05] ./app-demo() [0x9e92]
[06] /lib/libpthread.so.0(+0x61d0) [0x2aacd1d0]
Dump stack end...
app exit
Segmentation fault
檔案分析:
再虛擬機器上使用GNU工具集中的addr2line工具獲取原始碼位置
# addr2line -e app/app-demo 0xbc62
# /home/cql/smb/fuxi_h/demo-linux-wjc-20201211/app/main.c:538
附錄:
SIGHUP 1 A 終端掛起或者控制程序終止
SIGINT 2 A 鍵盤中斷(如break鍵被按下)正常終止
SIGQUIT 3 C 鍵盤的退出鍵被按下
SIGILL 4 C 非法指令
SIGABRT 6 C 由abort(3)發出的退出指令,異常終止
SIGIO 23,29,22 A 某I/O操作現在可以進行了(4.2 BSD)
SIGKILL 9 AEF 殺死程序的終極方法
SIGSEGV 11 C 無效的記憶體引用
SIGPIPE 13 A 管道破裂: 寫一個沒有讀埠的管道
SIGALRM 14 A 由alarm(2)發出的訊號
SIGTERM 15 A 終止訊號
SIGUSR1 30,10,16 A 使用者自定義訊號1給使用者做程序間通訊,不像其他的處理方法被綁定了
SIGUSR2 31,12,17 A 使用者自定義訊號2
SIGCHLD 20,17,18 B 子程序結束訊號
SIGCONT 19,18,25 程序繼續(曾被停止的程序)
SIGSTOP 17,19,23 DEF 終止程序
SIGTSTP 18,20,24 D 控制終端(tty)上按下停止鍵
SIGTTIN 21,21,26 D 後臺程序企圖從控制終端讀
SIGTTOU 22,22,27 D 後臺程序企圖從控制終端寫