2012-06-25 2 views
10

Die meisten Fehler, die in meinem C++ - Code auftreten, führen dazu, dass die App einfach beendet wird, ohne dass eine LogCat-Ausgabe erfolgt, und keine Nachricht auf dem Gerät. Nullzeiger und falsche Verwendung von JNI erzeugen oft dieses Ergebnis, und es ist unnötig zu sagen, dass es das Debuggen sehr schwierig macht.Kann ich einen C++ Stack-Trace erhalten, wenn die Android App abstürzt?

Derzeit kann ich eine Stack-Trace mit dem Befehl "bt" in ndk-gdb bekommen, aber nicht, wenn der Absturz innerhalb der ersten 2 Sekunden des Starts auftritt, weil ndk-gdb den Prozess startet und an ihn anfügt gestartet. Außerdem ist ndk-gdb unzuverlässig und sagt oft, es könne keine Symbole finden oder sich beispielsweise über nicht-tödliche "SIGILL" -Fehler beschweren.

Gibt es eine Möglichkeit, den Fehler aufzufangen und einen Stack-Trace oder andere Informationen zu drucken, wenn eine App abstürzt? Wenn zum Beispiel ein SIGSEGV vorhanden ist, würde ich gerne wissen, auf welche Adresse die App zugreifen wollte.

+1

überprüfen Sie diese Antwort. das ist speziell für android http://stackoverflow.com/a/28858941/365229 –

Antwort

4

trace.txt Datei etwas geben? Ich erinnere mich nicht, ob sein Standort ist: /data/anr/trace.txt oder /data/data/{pkg}/trace.txt

1

Sie müssen beginnen, indem Sie die SIGSEGV abfangen, um Code auszuführen, wenn Sie ein Segment erhalten. Dies ist Posix-Code, so etwas Ähnliches sollte auf Android funktionieren:

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

Die nächste Sache ist, dass die Funktion aufrufen, um die Signal-Handler zu registrieren. Du kannst es als erstes in main machen, aber dann bekommst du keine Stack-Spuren bis main. Wenn Sie sie zuvor möchten, können Sie diese Funktion vom Konstruktor eines globalen Objekts aufrufen. Aber es gibt keine Garantie, dass es der erste aufgerufene Konstruktor sein wird. Es gibt Möglichkeiten, um sicherzustellen, dass es früh aufgerufen wird. Zum Beispiel, Überladungs-Operator neu - in Debug-Builds - zuerst die Stack-Traces bei der ersten Zuweisung zu initialisieren und dann in den realen Operator neu aufzurufen. Dies gibt Ihnen Stack-Spuren, die bei der ersten Zuweisung beginnen.

einen Stack-Trace drucken:

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]): 
} 

Sie müssen mehr Arbeit tun, um die Symbole demangle sie lesbar zu machen. versuchen Sie abi :: __ cxa_demangle. Natürlich baue mit -g auf und verlinke mit -rdynamic.

+0

Danke. Ich habe den Fehler behoben, den ich gesucht habe, aber ich werde das nächste Mal definitiv versuchen. Ich bin mir nicht sicher, ob ich "-rdynamic" verstehe, obwohl ich in der Dokumentation nachgeschaut habe: "Übergeben Sie das Flag -export-dynamic an den ELF-Linker, auf Zielen, die es unterstützen. Das weist den Linker an, alle nicht nur verwendeten Symbole hinzuzufügen Einerseits in die dynamische Symboltabelle. Diese Option wird für einige Anwendungen von dlopen benötigt oder um das Zurückverfolgen von Daten innerhalb eines Programms zu ermöglichen. " ('-g', währenddessen," aktiviert Debugging-Informationen im bevorzugten Format für das Ziel ".) – Qwertie

+9

Mist! Backtrace sollte in execinfo.h sein, aber es existiert nicht auf Android! (execinfo.h: Keine solche Datei oder Verzeichnis) – Qwertie

+3

Ja, es gibt keine 'Backtrace' auf Android. –

-2

Ja 'execinfo.h' existiert nicht da, aber Callstack tut:

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

Hoffe, dass es in einem solchen Signal-Handler helfen kann.

+0

Ich muss etwas vermissen: fataler Fehler: utils/CallStack.h: Keine solche Datei oder Verzeichnis #include --- Vielleicht gibt es noch etwas, das in Android.mk oder so etwas gehen muss? –

+3

Es gibt keine Datei 'CallStack.h' im NDK-Ordner! –

+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 –

Verwandte Themen