הסעיפים הבאים כוללים סוגים נפוצים של התרסקות ילידים, ניתוח של מזבלה של התרסקות מדגם ודיון על מצבות. כל סוג קריסה כולל פלט לדוגמה debuggerd
עם ראיות מרכזיות מודגשות כדי לעזור לך להבחין בסוג הספציפי של התרסקות.
לְהַפִּיל
הפלות הן מעניינות כי הן מכוונות. ישנן דרכים רבות ושונות לביטול (כולל קריאת abort(3)
, כשל ב- assert(3)
, שימוש באחד מסוגי הרישום הקטלניים הספציפיים לאנדרואיד), אך כולן כוללות קריאת abort
. קריאה abort
מאותתת לשרשור הקורא עם SIGABRT, כך שמסגרת המציגה "abort" ב- libc.so
בתוספת SIGABRT הם הדברים שצריך לחפש בפלט debuggerd
כדי לזהות מקרה זה.
ייתכן שיש שורת "הודעת ביטול" מפורשת. אתה צריך גם להסתכל בפלט logcat
כדי לראות מה השרשור הזה רשם לפני שהרג את עצמו בכוונה, כי בניגוד assert(3)
או מתקני רישום קטלניים ברמה גבוהה, abort(3)
לא מקבל הודעה.
גרסאות נוכחיות של אנדרואיד משולבות בקריאה למערכת tgkill(2)
, כך שהערימות שלהן הן הקלות ביותר לקריאה, עם הקריאה לביטול(3) בחלק העליון:
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)
גרסאות ישנות יותר של אנדרואיד הלכו בנתיב מפותל בין שיחת הביטול המקורית (פריים 4 כאן) לבין שליחת האות בפועל (פריים 0 כאן). זה היה נכון במיוחד ב-ARM של 32 סיביות, שהוסיפה את __libc_android_abort
(מסגרת 3 כאן) לרצף של הפלטפורמות האחרות של raise
/ pthread_kill
/ tgkill
:
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
אתה יכול לשחזר מופע של סוג זה של התרסקות באמצעות crasher abort
.
הפניית מצביע אפס טהורה
זו הקריסה הילידים הקלאסית, ולמרות שזה רק מקרה מיוחד של סוג ההתרסקות הבא, כדאי להזכיר אותה בנפרד כי זה בדרך כלל דורש הכי פחות מחשבה.
בדוגמה למטה, למרות שהפונקציה הקורסת נמצאת ב- libc.so
, מכיוון שפונקציות המחרוזת פועלות רק על המצביעים שניתנו להן, אתה יכול להסיק ש- strlen(3)
נקרא עם מצביע null; והתרסקות זו אמורה לעבור ישירות למחבר הקוד המתקשר. במקרה זה, מסגרת #01 היא המתקשרת הרעה.
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)
אתה יכול לשחזר מופע של סוג זה של קריסה באמצעות crasher strlen-NULL
.
הפניית מצביע null עם כתובת נמוכה
במקרים רבים כתובת התקלה לא תהיה 0, אלא מספר נמוך אחר. כתובות דו או שלוש ספרות בפרט נפוצות מאוד, בעוד שכתובת בת שש ספרות היא כמעט בוודאות לא הפניית מצביע אפס - זה ידרוש היסט של 1MiB. זה קורה בדרך כלל כאשר יש לך קוד שמפנה מצביע null כאילו היה מבנה חוקי. פונקציות נפוצות הן fprintf(3)
(או כל פונקציה אחרת שלוקחת FILE*) ו- readdir(3)
, מכיוון שלעתים קרובות הקוד לא מצליח לבדוק שהקריאה fopen(3)
או opendir(3)
אכן הצליחה קודם.
הנה דוגמה ל- 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)
כאן הסיבה הישירה לקריסה היא ש- pthread_mutex_lock(3)
ניסה לגשת לכתובת 0xc (מסגרת 0). אבל הדבר הראשון pthread_mutex_lock
עושה הוא להצביע על רכיב state
של ה- pthread_mutex_t*
שהוא ניתן. אם אתה מסתכל על המקור, אתה יכול לראות שהאלמנט נמצא ב-offset 0 במבנה, מה שאומר לך של pthread_mutex_lock
קיבל את המצביע הלא חוקי 0xc. ממסגרת 1 ניתן לראות שהוא קיבל את המצביע הזה על ידי readdir
, אשר מחלץ את שדה mutex_
מה- DIR*
שהוא נתון. בהסתכלות על המבנה הזה, אתה יכול לראות ש- mutex_
נמצא ב-offset sizeof(int) + sizeof(size_t) + sizeof(dirent*)
לתוך struct DIR
, שבמכשיר 32 סיביות הוא 4 + 4 + 4 = 12 = 0xc, אז מצאת את הבאג: readdir
הועבר מצביע null על ידי המתקשר. בשלב זה אתה יכול להדביק את המחסנית לתוך כלי המחסנית כדי לגלות היכן ב-logcat זה קרה.
struct DIR { int fd_; size_t available_bytes_; dirent* next_; pthread_mutex_t mutex_; dirent buff_[15]; long current_pos_; };
ברוב המקרים אתה באמת יכול לדלג על הניתוח הזה. כתובת תקלה נמוכה מספיק פירושה בדרך כלל שאתה יכול פשוט לדלג על כל מסגרות libc.so
בערימה ולהאשים ישירות את הקוד המתקשר. אבל לא תמיד, וכך היית מציג מקרה משכנע.
אתה יכול לשחזר מופעים של סוג זה של קריסה באמצעות crasher fprintf-NULL
או crasher readdir-NULL
.
כישלון FORTIFY
כשל FORTIFY הוא מקרה מיוחד של הפסקה המתרחשת כאשר ספריית C מזהה בעיה שעלולה להוביל לפגיעות אבטחה. פונקציות רבות של ספריית C מבוצרות ; הם לוקחים טיעון נוסף שאומר להם כמה גדול המאגר באמת ובודקים בזמן הריצה האם הפעולה שאתה מנסה לבצע אכן מתאימה. הנה דוגמה שבה הקוד מנסה read(fd, buf, 32)
לתוך מאגר שאורכו למעשה רק 10 בתים...
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)
אתה יכול לשחזר מופע של סוג זה של קריסה באמצעות crasher fortify
.
שחיתות מחסנית זוהתה על ידי -fstack-protector
אפשרות -fstack-protector
של המהדר מכניסה צ'קים לפונקציות עם מאגרים על מחסנית כדי להגן מפני חריגות מאגר. אפשרות זו מופעלת כברירת מחדל עבור קוד פלטפורמה אך לא עבור אפליקציות. כאשר אפשרות זו מופעלת, המהדר מוסיף הוראות לפרולוג הפונקציה לכתוב ערך אקראי רק אחרי המקומי האחרון בערימה ולאפילוג הפונקציות כדי לקרוא אותו בחזרה ולבדוק שהוא לא השתנה. אם הערך הזה השתנה, הוא הוחלף על ידי הצפת מאגר, אז האפילוג קורא ל __stack_chk_fail
כדי להתחבר להודעה ולבטל.
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)
אתה יכול להבחין בין זה לבין סוגים אחרים של ביטול על ידי נוכחות של __stack_chk_fail
במעקב אחורה והודעת הביטול הספציפית.
אתה יכול לשחזר מופע של סוג זה של קריסה באמצעות crasher smash-stack
.
Seccomp SIGSYS משיחת מערכת אסורה
מערכת seccomp (במיוחד seccomp-bpf) מגבילה את הגישה לשיחות המערכת. למידע נוסף על seccomp למפתחי פלטפורמות, עיין בפוסט בבלוג Seccomp filter ב-Android O. שרשור הקורא לשיחת מערכת מוגבלת יקבל אות SIGSYS עם הקוד SYS_SECCOMP. מספר השיחה של המערכת יוצג בשורת הסיבה, יחד עם הארכיטקטורה. חשוב לציין שמספרי השיחות של המערכת משתנים בין הארכיטקטורות. לדוגמה, הקריאה למערכת readlinkat(2)
היא מספר 305 ב-x86 אך 267 ב-x86-64. מספר השיחה שונה שוב גם בזרוע וגם בזרוע64. מכיוון שמספרי שיחות המערכת משתנים בין ארכיטקטורות, בדרך כלל קל יותר להשתמש במעקב מחסנית כדי לגלות איזו קריאת מערכת נאסרה במקום לחפש את מספר שיחות המערכת בכותרות.
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)
אתה יכול להבחין בין קריאות מערכת אסורות לבין קריסות אחרות על ידי נוכחות של SYS_SECCOMP
על קו האות והתיאור על קו הסיבה.
אתה יכול לשחזר מופע של סוג זה של קריסה באמצעות crasher seccomp
.
הפרת זיכרון לביצוע בלבד (אנדרואיד 10 בלבד)
עבור arm64 באנדרואיד 10 בלבד, קטעי הפעלה של קבצים בינאריים וספריות מופו לזיכרון לביצוע בלבד (לא קריא) כטכניקת הקשחה נגד התקפות שימוש חוזר בקוד. הפחתה זו עשתה אינטראקציה גרועה עם תרופות אחרות והוסרה מאוחר יותר.
הפיכת הקוד לבלתי קריא גורמת לקריאה מכוונת ולא מכוונת לתוך מקטעי זיכרון המסומנים כ-execute בלבד כדי לזרוק SIGSEGV
עם הקוד SEGV_ACCERR
. זה עשוי להתרחש כתוצאה מבאג, פגיעות, נתונים מעורבים בקוד (כגון מאגר מילולי) או התבוננות פנימית בזיכרון מכוונת.
המהדר מניח שקוד ונתונים אינם מעורבים זה בזה, אך בעיות יכולות להיווצר מהרכבה בכתב יד. במקרים רבים ניתן לתקן אותם על ידי העברת הקבועים לקטע .data
. אם התבוננות פנימית של קוד נחוצה לחלוטין בקטעי קוד הניתנים להפעלה, יש לקרוא ל- mprotect(2)
תחילה כדי לסמן את הקוד קריא, ולאחר מכן שוב כדי לסמן אותו כבלתי קריא לאחר השלמת הפעולה.
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)
אתה יכול להבחין בין הפרות זיכרון לביצוע בלבד לבין קריסות אחרות לפי שורת הסיבה.
אתה יכול לשחזר מופע של סוג זה של קריסה באמצעות crasher xom
.
שגיאה זוהתה על ידי fdsan
חיטוי מתאר הקבצים של אנדרואיד עוזר לתפוס טעויות נפוצות עם מתארי קבצים כגון שימוש-אחרי-סגירה וסגירה כפולה. ראה את התיעוד של 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)
אתה יכול להבחין בין זה לבין סוגים אחרים של ביטול על ידי נוכחות של fdsan_error
במעקב אחורה והודעת הביטול הספציפית.
אתה יכול לשחזר מופע של סוג זה של קריסה באמצעות crasher fdsan_file
או crasher fdsan_dir
.
חוקרת מזבלות התרסקות
אם אין לך קריסה ספציפית שאתה חוקר כרגע, מקור הפלטפורמה כולל כלי לבדיקת debuggerd
בשם crasher. אם אתה mm
ב- system/core/debuggerd/
תקבל גם crasher
וגם crasher64
על הנתיב שלך (האחרון מאפשר לך לבדוק קריסות של 64 סיביות). Crasher יכול לקרוס במספר רב של דרכים מעניינות בהתבסס על הארגומנטים של שורת הפקודה שאתה מספק. השתמש crasher --help
כדי לראות את הבחירה הנתמכת כעת.
כדי להציג את החלקים השונים ב-crash dump, הבה נעבור דרך דוגמה זו של dump crash:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 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 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
שורת הכוכביות עם רווחים מועילה אם אתה מחפש ביומן קריסות מקוריות. המחרוזת "*** ***" לעתים נדירות מופיעה ביומנים מלבד בתחילת התרסקות מקומית.
Build fingerprint: 'Android/aosp_flounder/flounder:5.1.51/AOSP/enh08201009:eng/test-keys'
טביעת האצבע מאפשרת לך לזהות בדיוק על איזה מבנה התרחשה ההתרסקות. זה בדיוק כמו מאפיין מערכת ro.build.fingerprint
.
Revision: '0'
הגרסה מתייחסת לחומרה ולא לתוכנה. זה בדרך כלל לא בשימוש אבל יכול להיות שימושי כדי לעזור לך להתעלם אוטומטית מבאגים הידועים כנגרמים על ידי חומרה גרועה. זה בדיוק כמו מאפיין מערכת ro.revision
.
ABI: 'arm'
ה-ABI הוא אחד של arm, arm64, x86 או x86-64. זה שימושי בעיקר עבור סקריפט stack
שהוזכר לעיל, כך שהוא יודע באיזה כלים להשתמש.
pid: 1656, tid: 1656, name: crasher >>> crasher <<<
שורה זו מזהה את השרשור הספציפי בתהליך שקרס. במקרה זה, זה היה השרשור הראשי של התהליך, כך שמזהה התהליך ומזהה השרשור תואמים. השם הפרטי הוא שם השרשור, והשם מוקף >>> ו<<< הוא שם התהליך. עבור אפליקציה, שם התהליך הוא בדרך כלל שם החבילה המלא (כגון com.facebook.katana), דבר שימושי בעת הגשת באגים או ניסיון למצוא את האפליקציה ב-Google Play. ה-pid וה-tid יכולים להיות שימושיים גם במציאת קווי היומן הרלוונטיים שלפני ההתרסקות.
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
שורה זו מספרת לך איזה אות (SIGABRT) התקבל, ועוד על איך הוא התקבל (SI_TKILL). האותות המדווחים על ידי debuggerd
הם SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV ו- SIGTRAP. הקודים הספציפיים לאות משתנים בהתאם לאות הספציפי.
Abort message: 'some_file.c:123: some_function: assertion "false" failed'
לא לכל קריסות תהיה שורת הודעת ביטול, אבל ביטול. זה נאסף אוטומטית מהשורה האחרונה של פלט logcat קטלני עבור pid/tid זה, ובמקרה של הפלה מכוונת צפוי לתת הסבר מדוע התוכנית התאבדה.
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
ה-Registr dump מציג את התוכן של אוגרי ה-CPU בזמן קבלת האות. (סעיף זה משתנה מאוד בין ABIs.) עד כמה הם שימושיים יהיה תלוי בקריסה המדויקת.
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
העקיבה האחורית מראה לך היכן בקוד היינו בזמן ההתרסקות. העמודה הראשונה היא מספר המסגרת (תואם את הסגנון של gdb כאשר המסגרת העמוקה ביותר היא 0). ערכי המחשב הם יחסיים למיקום הספרייה המשותפת ולא כתובות מוחלטות. העמודה הבאה היא שם האזור הממוף (שהוא בדרך כלל ספרייה משותפת או קובץ הפעלה, אבל אולי לא מיועד, למשל, קוד הידור של JIT). לבסוף, אם סמלים זמינים, הסמל שאליו תואם ערך המחשב מוצג, יחד עם ההיסט לסמל זה בבתים. אתה יכול להשתמש בזה בשילוב עם objdump(1)
כדי למצוא את הוראת ה-assembler המתאימה.
קריאת מצבות
Tombstone written to: /data/tombstones/tombstone_06
זה אומר לך היכן debuggerd
כתב מידע נוסף. debuggerd
ישמור עד 10 מצבות, יעבור על המספרים 00 עד 09 ויחליף מצבות קיימות לפי הצורך.
המצבה מכילה את אותו מידע כמו מזבלה ההתרסקות, בתוספת כמה תוספות. לדוגמה, הוא כולל מעקבים לאחור עבור כל השרשורים (לא רק השרשור הקורס), אוגרי הנקודה הצפה, השלכות מחסניות גולמיות וזרימות זיכרון סביב הכתובות באוגרים. הכי שימושי זה כולל גם מפת זיכרון מלאה (בדומה ל- /proc/ pid /maps
). הנה דוגמה מוערת מקריסת תהליך ARM של 32 סיביות:
memory map: (fault address prefixed with --->) --->ab15f000-ab162fff r-x 0 4000 /system/xbin/crasher (BuildId: b9527db01b5cf8f5402f899f64b9b121)
יש לציין כאן שני דברים. הראשון הוא שלשורה זו יש קידומת "--->". המפות שימושיות ביותר כאשר ההתרסקות שלך היא לא רק הפניה של מצביע אפס. אם כתובת התקלה קטנה, כנראה שזו גרסה כלשהי של הפניית מצביע אפס. אחרת הסתכלות במפות סביב כתובת התקלה יכולה לתת לך לעתים קרובות רמז למה שקרה. כמה בעיות אפשריות שניתן לזהות על ידי התבוננות במפות כוללות:
- קורא/כותב מעבר לקצה של בלוק זיכרון.
- קורא/כותב לפני תחילת בלוק זיכרון.
- ניסיונות לבצע ללא קוד.
- בורח מקצה הערימה.
- ניסיונות לכתוב לקוד (כמו בדוגמה למעלה).
הדבר השני שיש לציין הוא שקובצי הפעלה וקבצי ספריות משותפות יציגו את ה-BuildId (אם קיים) באנדרואיד 6.0 ומעלה, כך שתוכל לראות בדיוק איזו גרסה של הקוד שלך קרסה. קבצי פלטפורמה בינאריים כוללים BuildId כברירת מחדל מאז Android 6.0; NDK r12 ומעלה מעביר אוטומטית -Wl,--build-id
גם למקשר.
ab163000-ab163fff r-- 3000 1000 /system/xbin/crasher ab164000-ab164fff rw- 0 1000 f6c80000-f6d7ffff rw- 0 100000 [anon:libc_malloc]
באנדרואיד הערימה היא לא בהכרח אזור בודד. אזורי ערימה יסווגו [anon:libc_malloc]
.
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
בדרך כלל, לספרייה משותפת יש שלושה ערכים צמודים. אחד ניתן לקריאה ולהפעלה (קוד), אחד הוא לקריאה בלבד (נתונים לקריאה בלבד), ואחד הוא קריאה-כתיבה (נתונים הניתנים לשינוי). העמודה הראשונה מציגה את טווחי הכתובות עבור המיפוי, העמודה השנייה את ההרשאות (בסגנון הרגיל של Unix ls(1)
), העמודה השלישית את ההיסט לקובץ (ב-hex), העמודה הרביעית את גודל האזור ( ב-hex), והעמודה החמישית הקובץ (או שם אזור אחר).
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]
החל מ-Android 5.0, ספריית C שמה את רוב האזורים הממופים האנונימיים שלה כך שיש פחות אזורי מסתורין.
f6fcb000-f6fccfff rw- 0 2000 [stack:5081]
אזורים בשם [stack: tid ]
הם הערימות עבור השרשורים הנתונים.
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]
אם אתה רואה [vector]
או [vdso]
תלוי בארכיטקטורה. ARM משתמש ב- [vector]
, בעוד שכל שאר הארכיטקטורות משתמשות ב- [vdso]
.