تشخیص تصادفات بومی

بخش‌های زیر شامل انواع متداول تصادف بومی، تجزیه و تحلیل نمونه‌ای از خرابی تصادف، و بحث درباره سنگ قبرها است. هر نوع خرابی شامل نمونه خروجی debuggerd با شواهد کلیدی است که به شما کمک می کند نوع خاصی از خرابی را تشخیص دهید.

سقط

سقط جنین جالب است زیرا عمدی است. راه‌های مختلفی برای سقط وجود دارد (از جمله فراخوانی abort(3) ، عدم موفقیت در assert(3) ، استفاده از یکی از انواع ثبت‌نام کشنده مخصوص اندروید)، اما همه شامل abort است. فراخوانی برای abort ، رشته فراخوان را با SIGABRT سیگنال می‌دهد، بنابراین قاب‌هایی که «abort» را در libc.so به‌علاوه SIGABRT نشان می‌دهند، چیزهایی هستند که باید در خروجی debuggerd برای تشخیص این مورد جستجو کنید.

ممکن است یک خط صریح "پیام سقط" وجود داشته باشد. همچنین باید به خروجی logcat نگاه کنید تا ببینید این رشته قبل از کشتن عمدی خود چه چیزی را ثبت کرده است، زیرا برخلاف assert(3) یا امکانات ثبت مرگبار سطح بالا، abort(3) پیامی را نمی پذیرد.

نسخه‌های کنونی Android تماس سیستمی 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) با یک اشاره گر تهی فراخوانی شده است. و این خرابی باید مستقیماً به نویسنده کد تماس برود. در این مورد، فریم شماره 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 بازتولید کنید.

عدم ارجاع نشانگر تهی آدرس پایین

در بسیاری از موارد آدرس خطا 0 نخواهد بود، بلکه یک عدد پایین دیگر خواهد بود. آدرس های دو یا سه رقمی به طور خاص بسیار رایج هستند، در حالی که یک آدرس شش رقمی تقریباً به طور قطع یک اشاره گر تهی نیست - که به یک مگا بایت آفست نیاز دارد. این معمولاً زمانی اتفاق می‌افتد که شما کدی دارید که یک اشاره‌گر تهی را به‌گونه‌ای که یک ساختار معتبر است، حذف می‌کند. توابع متداول عبارتند از 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_ در sizeof(int) + sizeof(size_t) + sizeof(dirent*) به struct DIR است، که در یک دستگاه 32 بیتی 4 + 4 + 4 = 12 = 0xc است. بنابراین شما اشکال را پیدا کردید: readdir یک اشاره گر تهی توسط تماس گیرنده ارسال شد. در این مرحله می توانید پشته را در ابزار stack بچسبانید تا بفهمید در کجای 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 در backtrace و پیام قطع خاص، این را از سایر انواع سقط متمایز کنید.

می‌توانید نمونه‌ای از این نوع خرابی را با استفاده از crasher smash-stack بازتولید کنید.

SIGSYS را از یک تماس سیستمی غیرمجاز جدا کنید

سیستم seccomp (به طور خاص seccomp-bpf) دسترسی به تماس های سیستم را محدود می کند. برای اطلاعات بیشتر درباره seccomp برای توسعه دهندگان پلتفرم، به پست وبلاگ فیلتر Seccomp در Android O مراجعه کنید. رشته ای که یک تماس سیستمی محدود را فراخوانی می کند یک سیگنال SIGSYS با کد SYS_SECCOMP دریافت می کند. شماره تماس سیستم در خط علت به همراه معماری نشان داده می شود. توجه به این نکته مهم است که شماره تماس سیستم بین معماری ها متفاوت است. به عنوان مثال، تماس سیستم readlinkat(2) شماره 305 در x86 اما 267 در x86-64 است. شماره تماس مجدداً در بازو و arm64 متفاوت است. از آنجایی که شماره تماس های سیستمی بین معماری ها متفاوت است، معمولاً استفاده از stack trace برای یافتن اینکه کدام تماس سیستمی مجاز نیست به جای جستجوی شماره تماس سیستم در سرصفحه ها آسان تر است.

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، بخش‌های اجرایی از باینری‌ها و کتابخانه‌ها به عنوان یک تکنیک سخت‌سازی در برابر حملات استفاده مجدد از کد در حافظه فقط اجرا (غیرقابل خواندن) نگاشت شدند. این کاهش با سایر اقدامات کاهشی تعامل بدی داشت و بعداً حذف شد.

ناخوانا کردن کد باعث می‌شود که خواندن‌های عمدی و غیرعمدی در بخش‌های حافظه که فقط اجرا علامت‌گذاری شده‌اند تا یک 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 اندروید به شناسایی اشتباهات رایج با توصیفگرهای فایل مانند استفاده پس از بسته شدن و دوبار بستن کمک می کند. برای جزئیات بیشتر در مورد اشکال زدایی (و اجتناب از) این دسته از خطاها، به مستندات 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 در backtrace و پیام abort خاص می توانید این را از انواع دیگر سقط تشخیص دهید.

می توانید نمونه ای از این نوع خرابی را با استفاده از crasher fdsan_file یا crasher fdsan_dir بازتولید کنید.

بررسی محل های تصادف

اگر در حال حاضر خرابی خاصی ندارید که در حال بررسی آن هستید، منبع پلتفرم شامل ابزاری برای آزمایش debuggerd به نام crasher است. اگر در system/core/debuggerd/ mm باشید، هم یک crasher و هم یک crasher64 در مسیر خود خواهید داشت (مورد دوم به شما امکان می دهد خرابی های 64 بیتی را آزمایش کنید). بر اساس آرگومان‌های خط فرمانی که ارائه می‌کنید، Craher می‌تواند به روش‌های زیادی از کار بیفتد. از crasher --help برای مشاهده گزینه های پشتیبانی شده فعلی استفاده کنید.

برای معرفی قطعات مختلف در یک تصادف، بیایید از طریق این نمونه تصادف کار کنیم:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
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 system است.

Revision: '0'

بازبینی به جای نرم افزار به سخت افزار اشاره دارد. این معمولاً استفاده نمی‌شود، اما می‌تواند برای کمک به نادیده گرفتن خودکار اشکال‌هایی که ناشی از سخت‌افزار بد هستند، مفید باشد. این دقیقاً مشابه ویژگی ro.revision system است.

ABI: 'arm'

ABI یکی از بازوها، 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 محتوای رجیسترهای CPU را در زمان دریافت سیگنال نشان می دهد. (این بخش بین ABI ها بسیار متفاوت است.) اینکه چقدر مفید هستند به خرابی دقیق بستگی دارد.

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 است). مقادیر PC به جای آدرس های مطلق نسبت به مکان کتابخانه مشترک است. ستون بعدی نام منطقه نگاشت شده است (که معمولاً یک کتابخانه مشترک یا قابل اجرا است، اما ممکن است مثلاً برای کد کامپایل شده JIT نباشد). در نهایت، اگر نمادها در دسترس باشند، نمادی که مقدار PC مربوط به آن است، همراه با افست در آن نماد در بایت نشان داده می شود. شما می توانید از این به همراه objdump(1) برای یافتن دستورالعمل اسمبلر مربوطه استفاده کنید.

خواندن سنگ قبرها

Tombstone written to: /data/tombstones/tombstone_06

این به شما می گوید که کجا debuggerd اطلاعات اضافی را نوشته است. debuggerd حداکثر 10 سنگ قبر را نگه می دارد، از اعداد 00 تا 09 عبور می کند و در صورت لزوم، سنگ قبرهای موجود را بازنویسی می کند.

سنگ قبر حاوی همان اطلاعات محل سقوط تصادف، به علاوه چند مورد اضافی است. به عنوان مثال، شامل بک‌تریس برای همه رشته‌ها (نه فقط رشته در حال خراب شدن)، ثبات‌های ممیز شناور، تخلیه‌های پشته خام، و تخلیه‌های حافظه در اطراف آدرس‌های موجود در ثبات‌ها است. مفیدتر از همه، یک نقشه حافظه کامل (شبیه به /proc/ pid /maps ) نیز دارد. در اینجا یک مثال مشروح از خرابی فرآیند 32 بیتی ARM آورده شده است:

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]

در Android، پشته لزوماً یک منطقه واحد نیست. مناطق پشته دارای برچسب [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

به طور معمول، یک کتابخانه مشترک دارای سه ورودی مجاور است. یکی خواندنی و قابل اجرا (کد)، یکی فقط خواندنی (داده های فقط خواندنی) و دیگری خواندنی و نوشتنی (داده های قابل تغییر). ستون اول محدوده آدرس برای نگاشت، ستون دوم مجوزها (در سبک معمول یونیکس ls(1) )، ستون سوم افست در فایل (به صورت هگز)، ستون چهارم اندازه منطقه ( در هگز)، و ستون پنجم فایل (یا نام منطقه دیگر).

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]

از اندروید 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] استفاده می کنند.