Linux內核調試方法總結之backtrace


backtrace

【用途】用戶態或者內核態程序異常退出時回溯堆棧信息

【原理】通過對當前堆棧的分析,回溯上層函數在當前棧中的幀地址,直至頂層函數。幀地址是指在棧中存在局部變量、上一級函數返回地址、寄存器值的內存空間。由於不同處理器堆棧實現不同(向上增長和向下增長),此功能的具體實現是編譯器內建的__buildin_frame_address及__buildin_return_address函數。如果編譯器不支持此函數,也可以自己實現該函數。

【接口說明】具體說明可以參考man backtrace幫助文檔

execinfo.h

int backtrace (void **buffer, int size)
The backtrace function obtains a backtrace for the current thread, as a list of pointers, and places the information into buffer.

char ** backtrace_symbols (void *const *buffer, int size)

The backtrace_symbols function translates the information obtained from the backtrace function into an array of strings. The argument buffer should be a pointer to an array of addresses obtained via the backtrace function, and size is the number of entries in that array (the return value of backtrace).

void backtrace_symbols_fd(void *const *buffer, int size, int fd)

【實例】

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <execinfo.h>

#include <fcntl.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

 

#define PRINT_DEBUG

#define MAX_BACKTRACE_LEVEL 10

#define BACKTRACE_LOG_NAME "backtrace.log"

 

static void show_reason(int sig, siginfo_t *info, void *secret){

    void *array[MAX_BACKTRACE_LEVEL];

    size_t size;

#ifdef PRINT_DEBUG

    char **strings;

    size_t i;

    size = backtrace(array, MAX_BACKTRACE_LEVEL);

    strings = backtrace_symbols(array, size);

    printf("Obtain %zd stack frames.\n", size);

    for(i = 0; i < size; i++)

    printf("%s\n", strings[i]);

    free(strings);

#else

    int fd = open(BACKSTRACE_LOG_NAME, O_CREAT | O_WRONLY);

    size = backtrace(array, MAX_BACKTRACE_LEVEL);

    backtrace_symbols_fd(array, size, fd);

    close(fd);

#endif

    exit(0);

}

 

void die() {

    char *str1;

    char *str2;

    char *str3;

    char *str4 = NULL;

    strcpy(str4, "ab");

}

 

void let_it_die() {

    die();

}

 

int main(int argc, char **argv){

    struct sigaction act;

    act.sa_sigaction = show_reason;

    sigemptyset(&act.sa_mask);

    act.sa_flags = SA_RESTART | SA_SIGINFO;

 

    sigaction(SIGSEGV, &act, NULL);

    sigaction(SIGUSR1, &act, NULL);

    sigaction(SIGFPE, &act, NULL);

  sigaction(SIGILL, &act, NULL);

    sigaction(SIGBUS, &act, NULL);

    sigaction(SIGABRT, &act, NULL);

    sigaction(SIGSYS, &act, NULL);

 

    let_it_die();

 

   return  0;

}

                                       

【調試】

1) 編譯

huawei@WUH1000002965:~/test$ gcc backtrace_test.c -o backtrace_test -g –rdynamic

(注:-rdynamic,這個option是傳遞給linker的,linker會將symbol放到.dydym table中,這樣backtrace_symbols才能獲取到地址對應的symbol。所以即使是使用了-g來編譯程序,如果不使用-rdynamic的話,backtrace_symbols也找不到地址對應的symbol。這是backtrace系列函數的一個缺陷)

2) 運行

huawei@WUH1000002965:~/test$ ./backtrace_test

Obtain 7 stack frames.

./backtrace_test() [0x40096e]

/lib/x86_64-linux-gnu/libc.so.6(+0x364a0) [0x7f2ff171c4a0]

./backtrace_test(die+0x18) [0x400a03]

./backtrace_test(let_it_die+0xe) [0x400a1d]

./backtrace_test(main+0xf6) [0x400b15]

/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f2ff170776d]

./backtrace_test() [0x400889]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM