2012-06-25 8 views
10

La mayoría de los errores que ocurren en mi código C++ hacen que la aplicación simplemente salga, sin ningún resultado de LogCat, y ningún mensaje en el dispositivo. Los punteros nulos y el uso incorrecto de JNI a menudo producen este resultado, y no hace falta decir que hace que la depuración sea muy difícil.¿Puedo obtener un seguimiento de pila de C++ cuando la aplicación de Android falla?

Actualmente puedo obtener un seguimiento de pila con el comando 'bt' en ndk-gdb, pero no si el bloqueo ocurre dentro de los primeros 2 segundos de inicio, porque ndk-gdb inicia el proceso y se conecta a él después de que empezado. Además, ndk-gdb no es confiable, a menudo dice que no puede encontrar ningún símbolo, o quejándose de errores "SIGILL" no fatales, por ejemplo.

¿Hay alguna manera de atrapar el error e imprimir un seguimiento de pila u otra información cuando una aplicación falla? Por ejemplo, si hay un SIGSEGV, me gustaría saber a qué dirección está intentando acceder la aplicación.

+1

marque esta respuesta. esto es específicamente para Android http://stackoverflow.com/a/28858941/365229 –

Respuesta

4

trace.txt file give something? No recuerdo si su ubicación es: /data/anr/trace.txt o /data/data/{pkg}/trace.txt

1

Debe comenzar atrapando el SIGSEGV para ejecutar el código cuando obtiene un segv. Este es el código POSIX, así que algo similar debería trabajar en android:

void abortHandler(int signum, siginfo_t* si, void* unused) 
{ 
    const char* name = NULL; 
    switch(signum) 
    { 
    case SIGABRT: name = "SIGABRT"; break; 
    case SIGSEGV: name = "SIGSEGV"; break; 
    case SIGBUS: name = "SIGBUS"; break; 
    case SIGILL: name = "SIGILL"; break; 
    case SIGFPE: name = "SIGFPE"; break; 
    case SIGPIPE: name = "SIGPIPE"; break; 
    } 

    if (name) 
     printf(stderr, "Caught signal %d (%s)\n", signum, name); 
    else 
     printf(stderr, "Caught signal %d\n", signum); 

    printStackTrace(stderr); 

    exit(signum); 
} 

void handleCrashes() 
{ 
    struct sigaction sa; 
    sa.sa_flags = SA_SIGINFO; 
    sa.sa_sigaction = abortHandler; 
    sigemptyset(&sa.sa_mask); 

    sigaction(SIGABRT, &sa, NULL); 
    sigaction(SIGSEGV, &sa, NULL); 
    sigaction(SIGBUS, &sa, NULL); 
    sigaction(SIGILL, &sa, NULL); 
    sigaction(SIGFPE, &sa, NULL); 
    sigaction(SIGPIPE, &sa, NULL); 
} 

El siguiente paso es llamar a esa función para registrar los manejadores de señales. Puedes hacerlo como lo primero en main, pero luego no obtendrás rastros de pila hasta main. Si los quiere antes, puede llamar a esta función desde el constructor de un objeto global. Pero no hay garantía de que será el primer constructor llamado. Hay formas de asegurarse de que se llame temprano. Por ejemplo, operador de sobrecarga nuevo - en compilaciones de depuración - para inicializar primero los rastreos de pila en la primera asignación, y luego llamar al operador real nuevo. Esto le dará rastros de pila comenzando en la primera asignación.

Para imprimir un seguimiento de pila:

void printStackTrace(unsigned int max_frames = 63) 
{ 
    void* addrlist[max_frames+1]; 

    // retrieve current stack addresses 
    u32 addrlen = backtrace(addrlist, sizeof(addrlist)/sizeof(void*)); 

    if (addrlen == 0) 
    { 
     printf(stderr, " <empty, possibly corrupt>\n"); 
     return; 
    } 

    char** symbollist = backtrace_symbols(addrlist, addrlen); 

    for (u32 i = 3; i < addrlen; i++) 
     printf(stderr, "%s\n", symbollist[i]): 
} 

Usted tendrá que trabajar más para demangle los símbolos para que puedan leerlo. prueba abi :: __ cxa_demangle. Por supuesto, compila con -g y enlaza con -dinámica.

+0

Gracias. Arreglé el error que estaba buscando pero definitivamente voy a intentarlo la próxima vez. No estoy seguro de entender '-rdynamic', aunque busqué la documentación:" Pase el indicador -export-dynamic al vinculador ELF, en los destinos que lo soportan. Esto le indica al vinculador que agregue todos los símbolos, no solo los utilizados. unos, a la tabla de símbolos dinámicos. Esta opción es necesaria para algunos usos de dlopen o para permitir la obtención de retrocesos desde un programa ". ('-g ', mientras tanto," activa la información de depuración en el formato preferido para el destino ".) – Qwertie

+9

¡Mierda! backtrace se supone que está en execinfo.h, ¡pero no existe en Android! (execinfo.h: No existe ese archivo o directorio) – Qwertie

+3

Sí, no hay 'backtrace' en Android. –

-2

Sí, 'execinfo.h' no existe allí, pero CallStack hace:

#include <utils/CallStack.h> 
.. 
CallStack cs; 
cs.dump(); 

esperan que los pueda ayudar en tales manejador de señales.

+0

Me falta algo: fatal error: utils/CallStack.h: No existe ningún archivo o directorio #include --- ¿Quizás hay algo más que necesite entrar en Android.mk o algo así? –

+3

¡No hay ningún archivo 'CallStack.h' en la carpeta NDK! –

+0

https://android.googlesource.com/platform/system/core.git/+/master/include/utils/CallStack.h https://android.googlesource.com/platform/frameworks/native/+/jb- dev/include/utils/CallStack.h –

Cuestiones relacionadas