אבחון קריסות מקומיות

קל לארגן דפים בעזרת אוספים אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.

הסעיפים הבאים כוללים סוגים נפוצים של התרסקות מקומיות, ניתוח של מזבלה של התרסקות מדגם ודיון על מצבות. כל סוג קריסה כולל פלט לדוגמה של 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

dump האוגר מציג את התוכן של אוגרי המעבד בזמן קבלת האות. (סעיף זה משתנה מאוד בין 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) כדי למצוא את הוראת ההרכבה המתאימה.

קריאת מצבות

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 כברירת מחדל מאז אנדרואיד 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] .