2011-06-06 104 views
13

我通過代碼處理SIGSEGV:如何獲得使用_Unwind_Backtrace fullstacktrace上SIGSEGV

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

int B() 
{ 
    return C(); 
} 

int A() 
{ 
    return B(); 
} 

int main(void) 
{ 
    struct sigaction handler; 
    memset(&handler,0,sizeof(handler)); 
    handler.sa_sigaction = handler_func; 
    handler.sa_flags = SA_SIGINFO; 
    sigaction(SIGSEGV,&handler,NULL); 
    return(C()); 
} 

如果處理代碼是:

static int handler_func(int signal, siginfo_t info, void* rserved) 
{ 
    const void* stack[MAX_DEPTH]; 
    StackCrowlState state; 
    state.addr = stack; 
    state.count = MAX_DEPTH; 

    _Unwind_Reason_Code code = _Unwind_Backtrace(trace_func,&state); 
    printf("Stack trace count: %d, code: %d\n",MAX_DEPTH - state.count, code); 

    kill(getpid(),SIGKILL); 
} 

static _Unwind_Reason_Code trace_func(void* context, void* arg) 
{ 
    StackCrowlState *state = (StackCrowlState *)arg; 
    if(state->count>0) 
    { 
    void *ip = (void *)_Unwind_GetIP(context); 
    if(ip) 
    { 
     state->addr[0] = ip; 
     state->count--; 
     state->addr++; 
    } 
    } 
    return(_URC_NO_REASON); 
} 

但trace_func這裏只調用一次,並只顯示在_Unwind_Backtrace調用。是否有可能使用_Unwind_Backtrace獲取導致SIGSEGV信號的代碼堆棧跟蹤?

日Thnx

回答

0

更好的使用回溯和backtrace_symbols_fd獲得從信號處理程序堆棧跟蹤。

+11

除了在使用GCC,因而有'_Unwind_Backtrace',但不是GNU庫,因而沒有'backtrace'和'backtrace_symbols_fd'平臺。 – 2012-11-22 13:11:39

5

您希望從信號觸發功能中回溯,但您從信號處理函數回溯。這是兩個不同的堆棧。 (請注意,sigaction中的SA_ONSTACK標誌與您的問題無關。)

要查找觸發函數的堆棧指針,請使用處理程序的第三個參數,即void * rserved。您可以參考此問題中的答案:Getting the saved instruction pointer address from a signal handler

+2

從信號處理程序的第三個參數中檢索到觸發函數的堆棧指針後,您知道該怎麼做?你仍然可以使用_Unwind_Backtrace?我有這個確切的問題,我看不出你的答案後真的​​不知道該怎麼做。 – P1r4nh4 2013-04-17 15:19:32

+0

這又過了一年+以後,我也不知道在這種情況下該怎麼做......我怎麼讓_Unwind_Backtrace實際上與舊的堆棧指針一起工作? – codetaku 2014-07-21 14:04:05

+0

還有一年和同樣的問題:我知道如何獲得SP,但我不知道該怎麼處理它! – 2015-04-10 08:28:24

0

您可以改爲使用__gnu_Unwind_Backtrace。爲ARM32例如:

typedef struct 
{ 
    uintptr_t r[16]; 
} core_regs; 

typedef struct 
{ 
    uintptr_t demand_save_flags; 
    core_regs core; 
} phase2_vrs; 

extern "C" _Unwind_Reason_Code __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, phase2_vrs * entry_vrs); 

int AndroidGetBackTraceWithContext(VOID **stack, UINT32 size, ucontext_t *ctx) 
{ 
    ANDROID_UNWIND_STATE state; 
    state.count = size; 
    state.stack = stack; 

    // First call stack is current pc 
    state.stack[0] = (VOID *)ctx->uc_mcontext.arm_pc; 
    state.stack++; 
    state.count--; 

    phase2_vrs pre_signal_state; 
    pre_signal_state.demand_save_flags = 0; 
    pre_signal_state.core = *reinterpret_cast<const core_regs*>(&(ctx->uc_mcontext.arm_r0)); 

    // Return value is of no use and might be wrong on some systems 
    __gnu_Unwind_Backtrace(DmpAndroidUnwindCallback, &state, &pre_signal_state); 

    return size - state.count; 
}