How to get fullstacktrace using _Unwind_Backtrace on SIGSEGV

前端 未结 4 599
长发绾君心
长发绾君心 2020-12-06 05:41

I handle SIGSEGV by code:

int C()
{
  int *i = NULL;
  *i = 10; // Crash there
}

int B()
{
  return C();
}

int A()
{
   return B();
}

int main(void)
{
  s         


        
4条回答
  •  鱼传尺愫
    2020-12-06 05:52

    If you want to use particularly _Unwind_Context(), you can do it like this (the code is 32-bit ARM specific):


    struct BacktraceState {
        const ucontext_t*   signal_ucontext;
        size_t              address_count = 0;
        static const size_t address_count_max = 30;
        uintptr_t           addresses[address_count_max] = {};
    
        BacktraceState(const ucontext_t* ucontext) : signal_ucontext(ucontext) {}
    
        bool AddAddress(uintptr_t ip) {
            // No more space in the storage. Fail.
            if (address_count >= address_count_max)
                return false;
    
            // Reset the Thumb bit, if it is set.
            const uintptr_t thumb_bit = 1;
            ip &= ~thumb_bit;
    
            // Ignore null addresses.
            // They sometimes happen when using _Unwind_Backtrace()
            // with the compiler optimizations,
            // when the Link Register is overwritten by the inner
            // stack frames.
            if (ip == 0)
                return true;
    
            // Ignore duplicate addresses.
            // They sometimes happen when using _Unwind_Backtrace()
            // with the compiler optimizations,
            // because we both add the second address from the Link Register
            // in ProcessRegisters() and receive the same address
            // in UnwindBacktraceCallback().
            if (address_count > 0 && ip == addresses[address_count - 1])
                return true;
    
            // Finally add the address to the storage.
            addresses[address_count++] = ip;
            return true;
        }
    };
    
    void ProcessRegisters(
            _Unwind_Context* unwind_context, BacktraceState* state) {
        assert(state);
        assert(unwind_context);
    
        const ucontext_t* signal_ucontext = state->signal_ucontext;
        assert(signal_ucontext);
    
        const sigcontext* signal_mcontext = &(signal_ucontext->uc_mcontext);
        assert(signal_mcontext);
    
        _Unwind_SetGR(unwind_context, REG_R0,  signal_mcontext->arm_r0);
        _Unwind_SetGR(unwind_context, REG_R1,  signal_mcontext->arm_r1);
        _Unwind_SetGR(unwind_context, REG_R2,  signal_mcontext->arm_r2);
        _Unwind_SetGR(unwind_context, REG_R3,  signal_mcontext->arm_r3);
        _Unwind_SetGR(unwind_context, REG_R4,  signal_mcontext->arm_r4);
        _Unwind_SetGR(unwind_context, REG_R5,  signal_mcontext->arm_r5);
        _Unwind_SetGR(unwind_context, REG_R6,  signal_mcontext->arm_r6);
        _Unwind_SetGR(unwind_context, REG_R7,  signal_mcontext->arm_r7);
        _Unwind_SetGR(unwind_context, REG_R8,  signal_mcontext->arm_r8);
        _Unwind_SetGR(unwind_context, REG_R9,  signal_mcontext->arm_r9);
        _Unwind_SetGR(unwind_context, REG_R10, signal_mcontext->arm_r10);
        _Unwind_SetGR(unwind_context, REG_R11, signal_mcontext->arm_fp);
        _Unwind_SetGR(unwind_context, REG_R12, signal_mcontext->arm_ip);
        _Unwind_SetGR(unwind_context, REG_R13, signal_mcontext->arm_sp);
        _Unwind_SetGR(unwind_context, REG_R14, signal_mcontext->arm_lr);
        _Unwind_SetGR(unwind_context, REG_R15, signal_mcontext->arm_pc);
    
        // Program Counter register aka Instruction Pointer will contain
        // the address of the instruction where the crash happened.
        // UnwindBacktraceCallback() will not supply us with it.
        state->AddAddress(signal_mcontext->arm_pc);
    
        // UnwindBacktraceCallback() does not always supply us with
        // the return address of the frame where the crash happened.
        // Sometimes Link Register will contain this address
        // (noticed when compiling with Clang without optimization),
        // but LR may also contain address of some previously visitied frame
        // (noticed when compiling with GCC without optimization),
        // or LR may contain null address
        // (noticed when compiling with Clang with optimization).
        // These heuristics are unreliable.
    #if __clang__
        state->AddAddress(signal_mcontext->arm_lr);
    #endif
    }
    
    _Unwind_Reason_Code UnwindBacktraceCallback(
            struct _Unwind_Context* unwind_context, void* state_voidp) {
        assert(unwind_context);
        assert(state_voidp);
    
        BacktraceState* state = (BacktraceState*)state_voidp;
        assert(state);
    
        // On the first UnwindBacktraceCallback() call,
        // set registers to _Unwind_Context and BacktraceState.
        if (state->address_count == 0) {
            ProcessRegisters(unwind_context, state);
            return _URC_NO_REASON;
        }
    
        uintptr_t ip = _Unwind_GetIP(unwind_context);
        bool ok = state->AddAddress(ip);
        if (!ok)
            return _URC_END_OF_STACK;
    
        return _URC_NO_REASON;
    }
    
    void CaptureBacktrace(BacktraceState* state) {
        assert(state);
        _Unwind_Backtrace(UnwindBacktraceCallback, state);
    }
    
    void SigActionHandler(int sig, siginfo_t* info, void* ucontext) {
        const ucontext_t* signal_ucontext = (const ucontext_t*)ucontext;
        assert(signal_ucontext);
    
        BacktraceState backtrace_state(signal_ucontext);
        CaptureBacktrace(&backtrace_state);
        // Do something with the backtrace - print, save to file, etc.
    }
    

    But I am advising you to not use _Unwind_Context(), but instead use precompiled libunwind for 32-bit ARM, bundled with modern Android NDKs (at sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libunwind.a). You will have to use use libc++ (LLVM STL). How to do it, is demonstrated in this my answer:

    https://stackoverflow.com/a/50027799/1016580

    If you use libstdc++ (GNU STL), use the Dar Hoo's solution:

    https://stackoverflow.com/a/48593413/1016580

提交回复
热议问题