2011-06-06 10 views
13

que manejo SIGSEGV por código:Como llegar fullstacktrace usando _Unwind_Backtrace en 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()); 
} 

Dónde código del controlador son:

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); 
} 

Pero trace_func donde llama sólo una vez, y muestra sólo en _Unwind_Backtrace llama. ¿Es posible obtener stacktrace de código que causa señal SIGSEGV usando _Unwind_Backtrace?

thnx

Respuesta

0

mejor utiliza traza y backtrace_symbols_fd para obtener una StackTrace de un manejador de señales.

+11

Excepto en plataformas que utilizar gcc, y por lo tanto tienen '_Unwind_Backtrace', pero no GNU libc, y por lo tanto no tienen' backtrace' y 'backtrace_symbols_fd'. –

5

Quiere retroceder desde la función de activación de la señal, pero retrocede desde la función del manejador de señal. Esas son dos pilas diferentes. (Tenga en cuenta que el indicador SA_ONSTACK en sigaction es irrelevante para su pregunta.)

Para buscar el puntero de la pila de la función desencadenante, use el tercer parámetro del controlador, es decir, void * rserved. Puede hacer referencia a la respuesta en esta pregunta: Getting the saved instruction pointer address from a signal handler

+2

¿Sabes qué hacer con el puntero de pila de la función de activación una vez que se recupera del tercer argumento del manejador de señal? ¿Todavía puedes usar _Unwind_Backtrace? Tengo este problema exacto y realmente no puedo entender qué hacer después de leer tu respuesta. – P1r4nh4

+0

Es un año más tarde y tampoco tengo idea de qué hacer en este caso ... ¿cómo hago que _Unwind_Backtrace realmente funcione con el antiguo puntero de pila? – codetaku

+0

Un año más y la misma pregunta: sé cómo obtener el SP, pero no sé qué hacer con él. –

0

Puede usar __gnu_Unwind_Backtrace en su lugar. Ejemplo para 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; 
}