Die folgenden Abschnitte enthalten Informationen zu gängigen Arten von nativen Abstürzen, eine Analyse eines Beispiel-Crash-Dumps und eine Erläuterung von Tombstones. Für jeden Absturztyp wird ein Beispiel für die debuggerd
-Ausgabe mit hervorgehobenen wichtigen Hinweisen angezeigt, damit Sie die Art des Absturzes unterscheiden können.
Abbrechen
Abbruchstests sind interessant, weil sie absichtlich durchgeführt werden. Es gibt viele verschiedene Möglichkeiten, einen Abbruch auszuführen (z. B. durch Aufrufen von abort(3)
, Scheitern einer assert(3)
oder Verwendung eines der Android-spezifischen fatalen Logging-Typen). Sie alle beinhalten jedoch den Aufruf von abort
. Ein Aufruf von abort
signalisiert dem aufrufenden Thread SIGABRT. In der debuggerd
-Ausgabe sollten Sie also nach einem Frame mit „abort“ in libc.so
und SIGABRT suchen, um diesen Fall zu erkennen.
Möglicherweise gibt es eine explizite Zeile „abort message“. Sehen Sie sich auch die logcat
-Ausgabe an, um zu sehen, was in diesem Thread protokolliert wurde, bevor er sich selbst beendet hat. Im Gegensatz zu assert(3)
oder den Protokollierungsfunktionen für kritische Fehler auf hoher Ebene akzeptiert abort(3)
keine Nachricht.
In aktuellen Android-Versionen wird der Systemaufruf tgkill(2)
inline eingefügt. Daher sind die Stacks am einfachsten zu lesen, wobei der Aufruf von abort(3) ganz oben steht:
pid: 4637, tid: 4637, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'some_file.c:123: some_function: assertion "false" failed' r0 00000000 r1 0000121d r2 00000006 r3 00000008 r4 0000121d r5 0000121d r6 ffb44a1c r7 0000010c r8 00000000 r9 00000000 r10 00000000 r11 00000000 ip ffb44c20 sp ffb44a08 lr eace2b0b pc eace2b16 backtrace: #00 pc 0001cb16 /system/lib/libc.so (abort+57) #01 pc 0001cd8f /system/lib/libc.so (__assert2+22) #02 pc 00001531 /system/bin/crasher (do_action+764) #03 pc 00002301 /system/bin/crasher (main+68) #04 pc 0008a809 /system/lib/libc.so (__libc_init+48) #05 pc 00001097 /system/bin/crasher (_start_main+38)
Bei älteren Android-Versionen gab es einen verwickelten Pfad zwischen dem ursprünglichen Abbruchaufruf (hier Frame 4) und der tatsächlichen Signalübertragung (hier Frame 0).
Das war besonders bei 32-Bit-ARM-Geräten der Fall, bei denen __libc_android_abort
(hier Frame 3) zur Sequenz raise
/pthread_kill
/tgkill
der anderen Plattformen hinzugefügt wurde:
pid: 1656, tid: 1656, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'some_file.c:123: some_function: assertion "false" failed' r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8 r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010 backtrace: #00 pc 00042c98 /system/lib/libc.so (tgkill+12) #01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32) #02 pc 0001bb87 /system/lib/libc.so (raise+10) #03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34) #04 pc 000168e8 /system/lib/libc.so (abort+4) #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16) #06 pc 00018d35 /system/lib/libc.so (__assert2+20) #07 pc 00000f21 /system/xbin/crasher #08 pc 00016795 /system/lib/libc.so (__libc_init+44) #09 pc 00000abc /system/xbin/crasher
Sie können einen solchen Absturz mit crasher
abort
reproduzieren.
Reine Dereferenzierung des Nullzeigers
Dies ist der klassische native Absturz. Obwohl er nur ein Sonderfall des nächsten Absturztyps ist, sollte er separat erwähnt werden, da er in der Regel am wenigsten Nachdenken erfordert.
Im folgenden Beispiel wird die Funktion, die zum Absturz führt, in libc.so
ausgeführt. Da die Stringfunktionen jedoch nur mit den übergebenen Pointern arbeiten, können Sie daraus schließen, dass strlen(3)
mit einem Nullzeiger aufgerufen wurde. Dieser Absturz sollte direkt an den Autor des aufrufenden Codes gesendet werden. In diesem Fall ist Frame 01 der fehlerhafte Aufrufer.
pid: 25326, tid: 25326, name: crasher >>> crasher <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 r0 00000000 r1 00000000 r2 00004c00 r3 00000000 r4 ab088071 r5 fff92b34 r6 00000002 r7 fff92b40 r8 00000000 r9 00000000 sl 00000000 fp fff92b2c ip ab08cfc4 sp fff92a08 lr ab087a93 pc efb78988 cpsr 600d0030 backtrace: #00 pc 00019988 /system/lib/libc.so (strlen+71) #01 pc 00001a8f /system/xbin/crasher (strlen_null+22) #02 pc 000017cd /system/xbin/crasher (do_action+948) #03 pc 000020d5 /system/xbin/crasher (main+100) #04 pc 000177a1 /system/lib/libc.so (__libc_init+48) #05 pc 000010e4 /system/xbin/crasher (_start+96)
Sie können einen solchen Absturz mit crasher
strlen-NULL
reproduzieren.
Dereferenzierung eines Nullzeigers mit niedriger Adresse
In vielen Fällen ist die Fehleradresse nicht 0, sondern eine andere niedrige Zahl. Insbesondere zwei- oder dreistellige Adressen sind sehr häufig, während eine sechsstellige Adresse fast sicher keine Nullzeiger-Dereferenzierung ist. Dafür wäre ein Offset von 1 MiB erforderlich. Das tritt in der Regel auf, wenn ein Code einen Nullzeiger so dereferenziert, als wäre er ein gültiger Datentyp. Gängige Funktionen sind fprintf(3)
(oder eine andere Funktion, die eine FILE*-Datei annimmt) und readdir(3)
, da im Code häufig nicht geprüft wird, ob der Aufruf von fopen(3)
oder opendir(3)
zuerst erfolgreich war.
Hier ein Beispiel für readdir
:
pid: 25405, tid: 25405, name: crasher >>> crasher <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc r0 0000000c r1 00000000 r2 00000000 r3 3d5f0000 r4 00000000 r5 0000000c r6 00000002 r7 ff8618f0 r8 00000000 r9 00000000 sl 00000000 fp ff8618dc ip edaa6834 sp ff8617a8 lr eda34a1f pc eda618f6 cpsr 600d0030 backtrace: #00 pc 000478f6 /system/lib/libc.so (pthread_mutex_lock+1) #01 pc 0001aa1b /system/lib/libc.so (readdir+10) #02 pc 00001b35 /system/xbin/crasher (readdir_null+20) #03 pc 00001815 /system/xbin/crasher (do_action+976) #04 pc 000021e5 /system/xbin/crasher (main+100) #05 pc 000177a1 /system/lib/libc.so (__libc_init+48) #06 pc 00001110 /system/xbin/crasher (_start+96)
Hier ist die direkte Ursache für den Absturz, dass pthread_mutex_lock(3)
versucht hat, auf die Adresse 0xc (Frame 0) zuzugreifen. Aber als Erstes löst pthread_mutex_lock
die Referenzierung des state
-Elements der übergebenen pthread_mutex_t*
auf. In der Quelle sehen Sie, dass sich das Element im Offset 0 der Struktur befindet. Das bedeutet, dass pthread_mutex_lock
der ungültige Pointer 0xc zugewiesen wurde. In Frame 1 sehen Sie, dass der Verweis von readdir
übergeben wurde, wodurch das Feld mutex_
aus dem übergebenen DIR*
extrahiert wird. Sie sehen, dass mutex_
bei einem Offset von sizeof(int) + sizeof(size_t) + sizeof(dirent*)
in struct DIR
liegt, was auf einem 32‑Bit-Gerät 4 + 4 + 4 = 12 = 0xc entspricht. Sie haben also den Fehler gefunden: readdir
wurde vom Aufrufer ein Nullzeiger übergeben. Sie können den Stack jetzt in das Stack-Tool einfügen, um herauszufinden, wo in logcat das Problem aufgetreten ist.
struct DIR { int fd_; size_t available_bytes_; dirent* next_; pthread_mutex_t mutex_; dirent buff_[15]; long current_pos_; };
In den meisten Fällen können Sie diese Analyse überspringen. Eine ausreichend niedrige Fehleradresse bedeutet in der Regel, dass Sie alle libc.so
-Frames im Stack einfach überspringen und den aufrufenden Code direkt beschuldigen können. Aber nicht immer. So können Sie einen überzeugenden Fall vorlegen.
Sie können diese Art von Absturz mit crasher
fprintf-NULL
oder crasher readdir-NULL
reproduzieren.
FORTIFY-Fehler
Ein FORTIFY-Fehler ist ein Sonderfall eines Abbruchs, der auftritt, wenn die C-Bibliothek ein Problem erkennt, das zu einer Sicherheitslücke führen kann. Viele C-Bibliotheksfunktionen sind fortified. Sie nehmen ein zusätzliches Argument an, das angibt, wie groß ein Puffer tatsächlich ist, und prüfen bei der Laufzeit, ob der durchzuführende Vorgang tatsächlich passt. Hier ein Beispiel, in dem der Code versucht, read(fd, buf, 32)
in einen Puffer zu schreiben, der nur 10 Byte lang ist:
pid: 25579, tid: 25579, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'FORTIFY: read: prevented 32-byte write into 10-byte buffer' r0 00000000 r1 000063eb r2 00000006 r3 00000008 r4 ff96f350 r5 000063eb r6 000063eb r7 0000010c r8 00000000 r9 00000000 sl 00000000 fp ff96f49c ip 00000000 sp ff96f340 lr ee83ece3 pc ee86ef0c cpsr 000d0010 backtrace: #00 pc 00049f0c /system/lib/libc.so (tgkill+12) #01 pc 00019cdf /system/lib/libc.so (abort+50) #02 pc 0001e197 /system/lib/libc.so (__fortify_fatal+30) #03 pc 0001baf9 /system/lib/libc.so (__read_chk+48) #04 pc 0000165b /system/xbin/crasher (do_action+534) #05 pc 000021e5 /system/xbin/crasher (main+100) #06 pc 000177a1 /system/lib/libc.so (__libc_init+48) #07 pc 00001110 /system/xbin/crasher (_start+96)
Sie können einen solchen Absturz mit crasher
fortify
reproduzieren.
Von -fstack-protector erkannte Stack-Beschädigung
Die Option -fstack-protector
des Compilers fügt Funktionen mit On-Stack-Puffern Prüfungen hinzu, um Pufferüberläufe zu verhindern. Diese Option ist standardmäßig für Plattformcode aktiviert, aber nicht für Apps. Wenn diese Option aktiviert ist, fügt der Compiler dem Prolog der Funktion Anweisungen hinzu, um einen zufälligen Wert direkt nach dem letzten lokalen Wert auf dem Stack zu schreiben, und dem Epilog der Funktion, um ihn wieder zu lesen und zu prüfen, ob er sich nicht geändert hat. Wenn sich dieser Wert geändert hat, wurde er durch einen Pufferüberlauf überschrieben. Daher ruft der Epilog __stack_chk_fail
auf, um eine Meldung zu protokollieren und abzubrechen.
pid: 26717, tid: 26717, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'stack corruption detected' r0 00000000 r1 0000685d r2 00000006 r3 00000008 r4 ffd516d8 r5 0000685d r6 0000685d r7 0000010c r8 00000000 r9 00000000 sl 00000000 fp ffd518bc ip 00000000 sp ffd516c8 lr ee63ece3 pc ee66ef0c cpsr 000e0010 backtrace: #00 pc 00049f0c /system/lib/libc.so (tgkill+12) #01 pc 00019cdf /system/lib/libc.so (abort+50) #02 pc 0001e07d /system/lib/libc.so (__libc_fatal+24) #03 pc 0004863f /system/lib/libc.so (__stack_chk_fail+6) #04 pc 000013ed /system/xbin/crasher (smash_stack+76) #05 pc 00001591 /system/xbin/crasher (do_action+280) #06 pc 00002219 /system/xbin/crasher (main+100) #07 pc 000177a1 /system/lib/libc.so (__libc_init+48) #08 pc 00001144 /system/xbin/crasher (_start+96)
Sie können diese Art von Abbruch anhand des Vorhandenseins von __stack_chk_fail
im Backtrace und der spezifischen Abbruchsmeldung unterscheiden.
Sie können einen solchen Absturz mit crasher
smash-stack
reproduzieren.
Seccomp-SIGSYS von einem nicht zulässigen Systemaufruf
Das seccomp-System (insbesondere seccomp-bpf) schränkt den Zugriff auf Systemaufrufe ein. Weitere Informationen zu seccomp für Plattformentwickler finden Sie im Blogpost Seccomp-Filter in Android O. Ein Thread, der einen eingeschränkten Systemaufruf ausführt, erhält ein SIGSYS-Signal mit dem Code SYS_SECCOMP. Die Systemaufrufnummer wird zusammen mit der Architektur in der Zeile „Ursache“ angezeigt. Die Systemaufrufnummern variieren je nach Architektur. Beispielsweise hat der Systemaufruf readlinkat(2)
unter x86 die Nummer 305, unter x86-64 aber 267.
Die Aufrufnummer ist sowohl bei arm als auch bei arm64 wieder unterschiedlich. Da die Systemaufrufnummern je nach Architektur variieren, ist es in der Regel einfacher, anhand des Stack-Traces herauszufinden, welcher Systemaufruf nicht zulässig war, als in den Headern nach der Systemaufrufnummer zu suchen.
pid: 11046, tid: 11046, name: crasher >>> crasher <<< signal 31 (SIGSYS), code 1 (SYS_SECCOMP), fault addr -------- Cause: seccomp prevented call to disallowed arm system call 99999 r0 cfda0444 r1 00000014 r2 40000000 r3 00000000 r4 00000000 r5 00000000 r6 00000000 r7 0001869f r8 00000000 r9 00000000 sl 00000000 fp fffefa58 ip fffef898 sp fffef888 lr 00401997 pc f74f3658 cpsr 600f0010 backtrace: #00 pc 00019658 /system/lib/libc.so (syscall+32) #01 pc 00001993 /system/bin/crasher (do_action+1474) #02 pc 00002699 /system/bin/crasher (main+68) #03 pc 0007c60d /system/lib/libc.so (__libc_init+48) #04 pc 000011b0 /system/bin/crasher (_start_main+72)
Sie können nicht zulässige Systemaufrufe von anderen Abstürzen anhand des Vorhandenseins von SYS_SECCOMP
in der Signalzeile und der Beschreibung in der Zeile mit der Ursache unterscheiden.
Sie können einen solchen Absturz mit crasher
seccomp
reproduzieren.
Verstoß gegen die XOM-Richtlinie (nur Android 10)
Nur für arm64 in Android 10 wurden ausführbare Segmente von Binärdateien und Bibliotheken als Härtungstechnik gegen Code-Reuse-Angriffe in den nur ausführbaren (nicht lesbaren) Speicher zugeordnet. Diese Abschwächung interagierte schlecht mit anderen Abschwächungen und wurde später entfernt.
Wenn Code unlesbar gemacht wird, führt dies zu vorsätzlichen und unbeabsichtigten Lesezugriffen auf Speichersegmente, die als „nur ausführen“ gekennzeichnet sind, um eine SIGSEGV
mit dem Code SEGV_ACCERR
zu werfen. Dies kann durch einen Fehler, eine Sicherheitslücke, Daten, die mit Code vermischt sind (z. B. ein Literalpool), oder eine vorsätzliche Speicherprüfung verursacht werden.
Der Compiler geht davon aus, dass Code und Daten nicht vermischt sind, aber Probleme können durch handgeschriebene Assemblercodes auftreten. In vielen Fällen können diese Probleme behoben werden, indem Sie die Konstanten einfach in einen .data
-Abschnitt verschieben.
Wenn die Code-Selbstprüfung für ausführbare Codeabschnitte unbedingt erforderlich ist, sollte mprotect(2)
zuerst aufgerufen werden, um den Code lesbar zu markieren, und dann noch einmal, um ihn nach Abschluss des Vorgangs unlesbar zu markieren.
pid: 2938, tid: 2940, name: crasher64 >>> crasher64 <<< signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x5f2ced24a8 Cause: execute-only (no-read) memory access error; likely due to data in .text. x0 0000000000000000 x1 0000005f2cecf21f x2 0000000000000078 x3 0000000000000053 x4 0000000000000074 x5 8000000000000000 x6 ff71646772607162 x7 00000020dcf0d16c x8 0000005f2ced24a8 x9 000000781251c55e x10 0000000000000000 x11 0000000000000000 x12 0000000000000014 x13 ffffffffffffffff x14 0000000000000002 x15 ffffffffffffffff x16 0000005f2ced52f0 x17 00000078125c0ed8 x18 0000007810e8e000 x19 00000078119fbd50 x20 00000078125d6020 x21 00000078119fbd50 x22 00000b7a00000b7a x23 00000078119fbdd8 x24 00000078119fbd50 x25 00000078119fbd50 x26 00000078119fc018 x27 00000078128ea020 x28 00000078119fc020 x29 00000078119fbcb0 sp 00000078119fba40 lr 0000005f2ced1b94 pc 0000005f2ced1ba4 backtrace: #00 pc 0000000000003ba4 /system/bin/crasher64 (do_action+2348) #01 pc 0000000000003234 /system/bin/crasher64 (thread_callback+44) #02 pc 00000000000e2044 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) #03 pc 0000000000083de0 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
Sie können nur-Ausführungsspeicherverstöße anhand der Zeile „Ursache“ von anderen Abstürzen unterscheiden.
Sie können einen solchen Absturz mit crasher xom
reproduzieren.
Von fdsan erkannter Fehler
Der fdsan-Dateideskriptor-Sanitizer von Android hilft, häufige Fehler mit Dateideskriptoren zu erkennen, z. B. die Verwendung nach dem Schließen und das doppelte Schließen. Weitere Informationen zum Beheben und Vermeiden dieser Art von Fehlern finden Sie in der Dokumentation zu fdsan.
pid: 32315, tid: 32315, name: crasher64 >>> crasher64 <<< signal 35 (), code -1 (SI_QUEUE), fault addr -------- Abort message: 'attempted to close file descriptor 3, expected to be unowned, actually owned by FILE* 0x7d8e413018' x0 0000000000000000 x1 0000000000007e3b x2 0000000000000023 x3 0000007fe7300bb0 x4 3033313465386437 x5 3033313465386437 x6 3033313465386437 x7 3831303331346538 x8 00000000000000f0 x9 0000000000000000 x10 0000000000000059 x11 0000000000000034 x12 0000007d8ebc3a49 x13 0000007fe730077a x14 0000007fe730077a x15 0000000000000000 x16 0000007d8ec9a7b8 x17 0000007d8ec779f0 x18 0000007d8f29c000 x19 0000000000007e3b x20 0000000000007e3b x21 0000007d8f023020 x22 0000007d8f3b58dc x23 0000000000000001 x24 0000007fe73009a0 x25 0000007fe73008e0 x26 0000007fe7300ca0 x27 0000000000000000 x28 0000000000000000 x29 0000007fe7300c90 sp 0000007fe7300860 lr 0000007d8ec2f22c pc 0000007d8ec2f250 backtrace: #00 pc 0000000000088250 /bionic/lib64/libc.so (fdsan_error(char const*, ...)+384) #01 pc 0000000000088060 /bionic/lib64/libc.so (android_fdsan_close_with_tag+632) #02 pc 00000000000887e8 /bionic/lib64/libc.so (close+16) #03 pc 000000000000379c /system/bin/crasher64 (do_action+1316) #04 pc 00000000000049c8 /system/bin/crasher64 (main+96) #05 pc 000000000008021c /bionic/lib64/libc.so (_start_main)
Sie können diese Art von Abbruch anhand des Vorhandenseins von fdsan_error
im Backtrace und der spezifischen Abbruchsmeldung unterscheiden.
Sie können einen solchen Absturz mit crasher fdsan_file
oder crasher fdsan_dir
reproduzieren.
Crash-Dumps untersuchen
Wenn Sie gerade keinen bestimmten Absturz untersuchen, enthält die Plattformquelle ein Tool zum Testen von debuggerd
namens „Crasher“. Wenn Sie mm
in system/core/debuggerd/
ausführen, wird sowohl crasher
als auch crasher64
in Ihrem Pfad angezeigt. Mit letzterem können Sie 64-Bit-Abstürze testen. Crasher kann auf viele interessante Arten abstürzen, je nachdem, welche Befehlszeilenargumente Sie angeben.
Mit crasher --help
kannst du die aktuell unterstützte Auswahl aufrufen.
Um die verschiedenen Teile eines Crash-Dumps zu veranschaulichen, sehen wir uns diesen Beispiel-Crash-Dump an:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: 'Android/aosp_flounder/flounder:5.1.51/AOSP/enh08201009:eng/test-keys' Revision: '0' ABI: 'arm' pid: 1656, tid: 1656, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'some_file.c:123: some_function: assertion "false" failed' r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8 r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010 backtrace: #00 pc 00042c98 /system/lib/libc.so (tgkill+12) #01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32) #02 pc 0001bb87 /system/lib/libc.so (raise+10) #03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34) #04 pc 000168e8 /system/lib/libc.so (abort+4) #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16) #06 pc 00018d35 /system/lib/libc.so (__assert2+20) #07 pc 00000f21 /system/xbin/crasher #08 pc 00016795 /system/lib/libc.so (__libc_init+44) #09 pc 00000abc /system/xbin/crasher Tombstone written to: /data/tombstones/tombstone_06 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Die Zeile mit Sternchen und Leerzeichen ist hilfreich, wenn Sie in einem Protokoll nach nativen Abstürzen suchen. Der String „*** ***“ wird nur selten in Protokollen angezeigt, außer zu Beginn eines nativen Absturzes.
Build fingerprint: 'Android/aosp_flounder/flounder:5.1.51/AOSP/enh08201009:eng/test-keys'
Anhand des Fingerabdrucks können Sie genau ermitteln, bei welchem Build der Absturz aufgetreten ist.
Dies entspricht genau der Systemeigenschaft ro.build.fingerprint
.
Revision: '0'
Die Revision bezieht sich auf die Hardware und nicht auf die Software. Diese Option wird in der Regel nicht verwendet, kann aber nützlich sein, um Fehler automatisch zu ignorieren, die bekanntermaßen durch fehlerhafte Hardware verursacht werden. Dies entspricht genau der Systemeigenschaft ro.revision
.
ABI: 'arm'
Das ABI ist eine der folgenden Optionen: arm, arm64, x86 oder x86-64. Das ist vor allem für das oben erwähnte stack
-Script nützlich, damit es weiß, welche Toolchain verwendet werden soll.
pid: 1656, tid: 1656, name: crasher >>> crasher <<<
Diese Zeile gibt den spezifischen Thread im Prozess an, der abgestürzt ist. In diesem Fall war es der Hauptthread des Prozesses, sodass die Prozess- und Thread-ID übereinstimmen. Der erste Name ist der Threadname und der Name, der von >>> und <<< umgeben ist, ist der Prozessname. Bei einer App ist der Prozessname in der Regel der vollständige Paketname (z. B. com.facebook.katana). Das ist hilfreich, wenn Sie Fehler melden oder die App in Google Play suchen möchten. Die PID und die TID können auch hilfreich sein, um die relevanten Logzeilen vor dem Absturz zu finden.
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
In dieser Zeile sehen Sie, welches Signal (SIGABRT) empfangen wurde und wie es empfangen wurde (SI_TKILL). Die von debuggerd
gemeldeten Signale sind SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV und SIGTRAP. Die signalspezifischen Codes variieren je nach Signal.
Abort message: 'some_file.c:123: some_function: assertion "false" failed'
Nicht alle Abstürze enthalten eine Abbruchsnachricht, aber Abbruchsmeldungen schon. Dieser Wert wird automatisch aus der letzten Zeile der fatalen Logcat-Ausgabe für diese PID/TID erfasst. Im Falle einer absichtlichen Abbruchs wird hier wahrscheinlich eine Erklärung dafür angezeigt, warum das Programm beendet wurde.
r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8 r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010
Der Registerdump zeigt den Inhalt der CPU-Register zum Zeitpunkt des Empfangs des Signals. (Dieser Abschnitt variiert stark zwischen ABIs.) Wie nützlich diese sind, hängt vom genauen Absturz ab.
backtrace: #00 pc 00042c98 /system/lib/libc.so (tgkill+12) #01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32) #02 pc 0001bb87 /system/lib/libc.so (raise+10) #03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34) #04 pc 000168e8 /system/lib/libc.so (abort+4) #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16) #06 pc 00018d35 /system/lib/libc.so (__assert2+20) #07 pc 00000f21 /system/xbin/crasher #08 pc 00016795 /system/lib/libc.so (__libc_init+44) #09 pc 00000abc /system/xbin/crasher
Der Backtrace zeigt an, wo im Code wir uns zum Zeitpunkt des Absturzes befanden. Die erste Spalte ist die Frame-Nummer (entspricht dem Stil von gdb, bei dem der tiefste Frame 0 ist). Die PC-Werte sind nicht absolut, sondern relativ zum Speicherort der freigegebenen Bibliothek. Die nächste Spalte ist der Name der zugeordneten Region. In der Regel ist dies eine freigegebene Bibliothek oder eine ausführbare Datei, aber möglicherweise nicht für JIT-kompilierten Code. Wenn Symbole verfügbar sind, wird das Symbol angezeigt, dem der PC-Wert entspricht, zusammen mit dem Offset in diesem Symbol in Byte. Sie können dies in Verbindung mit objdump(1)
verwenden, um die entsprechende Assembleranweisung zu finden.
Tombstones lesen
Tombstone written to: /data/tombstones/tombstone_06
Hier sehen Sie, wo debuggerd
zusätzliche Informationen hinzugefügt hat.
debuggerd
speichert bis zu zehn Tombstones, wobei die Zahlen 00 bis 09 durchlaufen und vorhandene Tombstones bei Bedarf überschrieben werden.
Der Tombstone enthält dieselben Informationen wie der Crash-Dump, zusätzlich aber noch einige weitere. Dazu gehören beispielsweise Backtraces für alle Threads (nicht nur für den Thread, der abgestürzt ist), die Gleitkommaregister, Roh-Stack-Dumps und Speicher-Dumps um die Adressen in den Registern. Am nützlichsten ist es, wenn auch eine vollständige Speicherzuordnung enthalten ist (ähnlich wie bei /proc/pid/maps
). Hier ein kommentiertes Beispiel für einen Absturz eines 32-Bit-ARM-Prozesses:
memory map: (fault address prefixed with --->) --->ab15f000-ab162fff r-x 0 4000 /system/xbin/crasher (BuildId: b9527db01b5cf8f5402f899f64b9b121)
Hier sind zwei Dinge zu beachten. Erstens: Diese Zeile beginnt mit „--->“. Die Maps sind am nützlichsten, wenn der Absturz nicht nur auf eine Nullzeiger-Dereferenzierung zurückzuführen ist. Wenn die Fehleradresse klein ist, handelt es sich wahrscheinlich um eine Variante der Dereferenzierung eines Nullzeigers. Andernfalls können Sie sich die Karten in der Nähe der Fehleradresse ansehen, um herauszufinden, was passiert ist. Einige mögliche Probleme, die anhand der Karten erkannt werden können:
- Liest/schreibt über das Ende eines Speicherblocks hinaus.
- Lesen/Schreiben vor dem Beginn eines Speicherblocks.
- Versuche, nicht-codierte Inhalte auszuführen.
- Sie stoßen am Ende eines Stapels an.
- Es wird versucht, in den Code zu schreiben (wie im Beispiel oben).
Zweitens: In Android 6.0 und höher wird in ausführbaren Dateien und freigegebenen Bibliotheksdateien die Build-ID (falls vorhanden) angezeigt. So können Sie genau sehen, welche Version Ihres Codes abgestürzt ist. Plattformbinärdateien enthalten seit Android 6.0 standardmäßig eine Build-ID. NDK r12 und höher übergeben -Wl,--build-id
auch automatisch an den Linker.
ab163000-ab163fff r-- 3000 1000 /system/xbin/crasher ab164000-ab164fff rw- 0 1000 f6c80000-f6d7ffff rw- 0 100000 [anon:libc_malloc]
Unter Android ist der Heap nicht unbedingt eine einzelne Region. Heap-Regionen werden mit [anon:libc_malloc]
gekennzeichnet.
f6d82000-f6da1fff r-- 0 20000 /dev/__properties__/u:object_r:logd_prop:s0 f6da2000-f6dc1fff r-- 0 20000 /dev/__properties__/u:object_r:default_prop:s0 f6dc2000-f6de1fff r-- 0 20000 /dev/__properties__/u:object_r:logd_prop:s0 f6de2000-f6de5fff r-x 0 4000 /system/lib/libnetd_client.so (BuildId: 08020aa06ed48cf9f6971861abf06c9d) f6de6000-f6de6fff r-- 3000 1000 /system/lib/libnetd_client.so f6de7000-f6de7fff rw- 4000 1000 /system/lib/libnetd_client.so f6dec000-f6e74fff r-x 0 89000 /system/lib/libc++.so (BuildId: 8f1f2be4b37d7067d366543fafececa2) (load base 0x2000) f6e75000-f6e75fff --- 0 1000 f6e76000-f6e79fff r-- 89000 4000 /system/lib/libc++.so f6e7a000-f6e7afff rw- 8d000 1000 /system/lib/libc++.so f6e7b000-f6e7bfff rw- 0 1000 [anon:.bss] f6e7c000-f6efdfff r-x 0 82000 /system/lib/libc.so (BuildId: d189b369d1aafe11feb7014d411bb9c3) f6efe000-f6f01fff r-- 81000 4000 /system/lib/libc.so f6f02000-f6f03fff rw- 85000 2000 /system/lib/libc.so f6f04000-f6f04fff rw- 0 1000 [anon:.bss] f6f05000-f6f05fff r-- 0 1000 [anon:.bss] f6f06000-f6f0bfff rw- 0 6000 [anon:.bss] f6f0c000-f6f21fff r-x 0 16000 /system/lib/libcutils.so (BuildId: d6d68a419dadd645ca852cd339f89741) f6f22000-f6f22fff r-- 15000 1000 /system/lib/libcutils.so f6f23000-f6f23fff rw- 16000 1000 /system/lib/libcutils.so f6f24000-f6f31fff r-x 0 e000 /system/lib/liblog.so (BuildId: e4d30918d1b1028a1ba23d2ab72536fc) f6f32000-f6f32fff r-- d000 1000 /system/lib/liblog.so f6f33000-f6f33fff rw- e000 1000 /system/lib/liblog.so
Eine freigegebene Bibliothek hat in der Regel drei benachbarte Einträge. Eine ist lesbar und ausführbar (Code), eine ist schreibgeschützt (schreibgeschützte Daten) und eine ist les- und schreibbar (änderbare Daten). In der ersten Spalte sind die Adressbereiche für die Zuordnung, in der zweiten Spalte die Berechtigungen (im üblichen Unix-ls(1)
-Format), in der dritten Spalte der Offset in der Datei (hexadezimal), in der vierten Spalte die Größe der Region (hexadezimal) und in der fünften Spalte die Datei (oder ein anderer Regionsname) aufgeführt.
f6f34000-f6f53fff r-x 0 20000 /system/lib/libm.so (BuildId: 76ba45dcd9247e60227200976a02c69b) f6f54000-f6f54fff --- 0 1000 f6f55000-f6f55fff r-- 20000 1000 /system/lib/libm.so f6f56000-f6f56fff rw- 21000 1000 /system/lib/libm.so f6f58000-f6f58fff rw- 0 1000 f6f59000-f6f78fff r-- 0 20000 /dev/__properties__/u:object_r:default_prop:s0 f6f79000-f6f98fff r-- 0 20000 /dev/__properties__/properties_serial f6f99000-f6f99fff rw- 0 1000 [anon:linker_alloc_vector] f6f9a000-f6f9afff r-- 0 1000 [anon:atexit handlers] f6f9b000-f6fbafff r-- 0 20000 /dev/__properties__/properties_serial f6fbb000-f6fbbfff rw- 0 1000 [anon:linker_alloc_vector] f6fbc000-f6fbcfff rw- 0 1000 [anon:linker_alloc_small_objects] f6fbd000-f6fbdfff rw- 0 1000 [anon:linker_alloc_vector] f6fbe000-f6fbffff rw- 0 2000 [anon:linker_alloc] f6fc0000-f6fc0fff r-- 0 1000 [anon:linker_alloc] f6fc1000-f6fc1fff rw- 0 1000 [anon:linker_alloc_lob] f6fc2000-f6fc2fff r-- 0 1000 [anon:linker_alloc] f6fc3000-f6fc3fff rw- 0 1000 [anon:linker_alloc_vector] f6fc4000-f6fc4fff rw- 0 1000 [anon:linker_alloc_small_objects] f6fc5000-f6fc5fff rw- 0 1000 [anon:linker_alloc_vector] f6fc6000-f6fc6fff rw- 0 1000 [anon:linker_alloc_small_objects] f6fc7000-f6fc7fff rw- 0 1000 [anon:arc4random _rsx structure] f6fc8000-f6fc8fff rw- 0 1000 [anon:arc4random _rs structure] f6fc9000-f6fc9fff r-- 0 1000 [anon:atexit handlers] f6fca000-f6fcafff --- 0 1000 [anon:thread signal stack guard page]
Seit Android 5.0 benennt die C-Bibliothek die meisten ihrer anonym zugeordneten Regionen, sodass es weniger unbekannte Regionen gibt.
f6fcb000-f6fccfff rw- 0 2000 [stack:5081]
Regionen mit dem Namen [stack:tid]
sind die Stacks für die angegebenen Threads.
f6fcd000-f702afff r-x 0 5e000 /system/bin/linker (BuildId: 84f1316198deee0591c8ac7f158f28b7) f702b000-f702cfff r-- 5d000 2000 /system/bin/linker f702d000-f702dfff rw- 5f000 1000 /system/bin/linker f702e000-f702ffff rw- 0 2000 f7030000-f7030fff r-- 0 1000 f7031000-f7032fff rw- 0 2000 ffcd7000-ffcf7fff rw- 0 21000 ffff0000-ffff0fff r-x 0 1000 [vectors]
Ob [vector]
oder [vdso]
angezeigt wird, hängt von der Architektur ab. ARM verwendet [vector]
, während alle anderen Architekturen [vdso]
verwenden.