使用_Unwind_Backtrace函数抓取C/C++堆栈的backtrace

郎弘业
2023-12-01

代码示例

#include <stdio.h>
#include <unwind.h>
#include <stdint.h>

#include <signal.h>

struct sigaction act_old;


static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) {

    uintptr_t pc = _Unwind_GetIP(context);
    if (pc) {
        printf("unwind got pc ...0x%x\n", pc);
    }

    return _URC_NO_REASON;
}

ssize_t unwind_backtrace() {

    _Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, 0);

    return rc == _URC_END_OF_STACK ? 0 : -1;
}

void func_1() {
    int ret = unwind_backtrace();
    printf("unwind_backtrace return ...%d\n", ret);
}

void func_2() {
   func_1();
}

static void crash_handler_more(int sig, struct siginfo* info, void* buf) {

    unwind_backtrace();

    sigaction(sig, &act_old, 0);
}

void initCrashHandler() {
    struct sigaction act;
    act.sa_sigaction = crash_handler_more;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGKILL, &act, 0);
    sigaction(SIGINT, &act, 0);
    sigaction(SIGQUIT, &act, 0);
    sigaction(SIGILL, &act, 0);
    sigaction(SIGABRT, &act, 0);
    sigaction(SIGBUS, &act, 0);
    sigaction(SIGSEGV, &act, &act_old);
}

void triggerCrash() {
    char *p = 0;
    p[100] = 'a';
}

int main() {

    initCrashHandler();

    func_2();
    
    triggerCrash();
    return 0;
}

示例代码在正常调用和程序crash两种情况下抓取函数调用的backtrace, 程序崩溃的backtrace可以保存下来用于分析崩溃问题.可以用dladdr函数通过pc值提取出Dl_info, 从而拿到函数符号名, 也可以通过 addr2line工具进行转换.
由于android系统的libc不是标准的gnulibc, 常用的backtrace抓取函数android系统并不支持, 经过验证, _Unwind_Backtrace可以在android系统正常使用, backtrace的所有pc值都可以被准确获取.

 类似资料: