1. 程式人生 > 實用技巧 >linux應用程式除錯----backtrace

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 後臺程序企圖從控制終端寫