2013-08-02 12 views
6

Sto cercando di rilevare segnali come SIGSEGV nella mia app Android NDK per scopi di debug. Per quello, ho impostato una sigaction che viene chiamata.Android _Unwind_Backtrace inside sigaction

Ora sto cercando di ottenere lo stack della chiamata. Il problema è che _Unwind_Backtrace funziona solo su stack correnti e sessioni di sigaction all'interno del proprio stack.

Quindi, c'è un modo per ottenere la pila del puntatore di esecuzione che ha ricevuto il segnale? (Fondamentalmente dire _Unwind_Backtrace per rilassarsi un'altra pila di quello attuale?)

Tengo a precisare che:

  • utilizzando backtrace() e backtrace_symbols() non è un'opzione in quanto tali funzioni non sono consegnati in Android NDK

  • Sto utilizzando GDB per indagare sugli arresti anomali sui dispositivi locali. Non voglio sostituire GDB, voglio essere in grado di ricevere tracce di stack significative dal client quando gli mando una build di test.

EDIT: Ho provato con libcorkscrew di Android dal sistema/core, come proposto dal Fadden, ma quando uso la sua funzione unwind_backtrace_signal_arch, ottengo uno strano backtrace che non rappresentano l'incidente.

risposta

3

È possibile ottenere l'indirizzo di base dello stack con pthread_getattr_np e pthread_attr_getstack, ma ciò di cui si ha realmente bisogno è il PC e SP al momento dello schianto. Su Linux, puoi estrarli dallo ucontext.

Se si imposta il flag SA_SIGINFO quando si configura il gestore di segnale, la funzione di gestore ottiene tre argomenti anziché uno. Il terzo argomento void* è un puntatore ucontext. La risposta accettata allo this question spiega un po 'di più.

Una volta ottenuto tutto ciò che è possibile rilassarsi lo stack. Se non ti dispiace fare un passo fuori dai limiti di ciò che fornisce NDK, Android libcorkscrew ha funzioni in grado di srotolare stack e produrre risultati. Viene utilizzato dal daemon debuggerd per eseguire il dump degli arresti anomali nativi nel file di registro.

Potrebbe essere utile sapere che i crash nativi registrati da debuggerd generano i dump dello stack in /data/tombstones/. Le autorizzazioni per il file lo rendono inaccessibile alle normali app, ma su un dispositivo modificato potresti semplicemente estrarle e inviarle.

+3

Ho cercato ma non riesco a capire dalla tua risposta come scaricare una pila con un puntatore ucontext. Hai qualche esempio? –

+0

ucontext.h non è fornito in bionico, che è ciò che Android utilizza. Sono anche molto interessato a come estrarre informazioni da questa struttura su una piattaforma in cui la struttura non esiste. Devo fidarmi che sia lo stesso membro che ordina come in Linux, e basta estrarre il PC e l'SP dall'indirizzo di memoria? – codetaku

+0

ucontext.h fa parte di bionic, anche se potrebbe non essere disponibile da NDK (consultare https://android.googlesource.com/platform/bionic/+/kitkat-release/libc/kernel/arch-arm/asm/ucontext.h). Non che faccia molto bene - ha una definizione piuttosto generica. AFAIK non esiste alcuna personalizzazione specifica per Android per ucontext. – fadden

2

Nella mia pratica, _Unwind_Backtrace non è riuscito a passare allo stack di pre-segnale.

Sono riuscito ad ottenere alcuni stack di segnale precedente chiamando libgcc interno __gnu_Unwind_Backtrace - ha un valore aggiuntivo che è "valori di registro correnti" - quindi funziona su uno stack dato, non sullo stack corrente.

//definitions copied from arm-specific libgcc 4.8 sources. 
struct core_regs 
{ 
    _uw r[16]; 
}; 

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

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

// Getting backtrace with those definitions 
//istead of _Unwind_Backtrace(tracer, &state); 
if (const ucontext_t* signal_context = last_sigaction_parameter) 
{ 
     phase2_vrs pre_signal_state = {}; 
     pre_signal_state.core = *reinterpret_cast<const core_regs*>(&(signal_context->uc_mcontext.arm_r0)); 
     __gnu_Unwind_Backtrace(tracer, &state, &pre_signal_state); 
}