Các phần sau đây bao gồm các loại sự cố mã gốc thường gặp, phân tích tệp báo lỗi sự cố mẫu và thảo luận về tệp tombstone. Mỗi loại sự cố bao gồm ví dụ về đầu ra debuggerd
với bằng chứng chính được làm nổi bật để giúp bạn phân biệt loại sự cố cụ thể.
Hủy
Việc huỷ là thú vị vì đó là hành động có chủ ý. Có nhiều cách để huỷ (bao gồm cả việc gọi abort(3)
, không thành công với assert(3)
, sử dụng một trong các loại ghi nhật ký nghiêm trọng dành riêng cho Android), nhưng tất cả đều liên quan đến việc gọi abort
. Lệnh gọi đến abort
sẽ báo hiệu luồng gọi bằng SIGABRT, vì vậy, khung hiển thị "abort" (huỷ) trong libc.so
cùng với SIGABRT là những điều cần tìm trong đầu ra debuggerd
để nhận ra trường hợp này.
Có thể có một dòng "thông báo huỷ" rõ ràng. Bạn cũng nên xem trong đầu ra logcat
để biết luồng này đã ghi lại nội dung gì trước khi tự huỷ, vì không giống như assert(3)
hoặc các cơ sở ghi nhật ký nghiêm trọng cấp cao, abort(3)
không chấp nhận thông báo.
Các phiên bản Android hiện tại cùng dòng với lệnh gọi hệ thống tgkill(2)
, vì vậy, ngăn xếp của các phiên bản này dễ đọc nhất, với lệnh gọi đến abort(3) ở trên cùng:
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)
Các phiên bản Android cũ hơn đã đi theo một lộ trình phức tạp giữa lệnh gọi huỷ ban đầu (khung 4 ở đây) và việc gửi tín hiệu thực tế (khung 0 ở đây).
Điều này đặc biệt đúng trên ARM 32 bit, trong đó thêm __libc_android_abort
(khung 3 ở đây) vào trình tự raise
/pthread_kill
/tgkill
của các nền tảng khác:
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
Bạn có thể tái tạo một thực thể của loại sự cố này bằng crasher
abort
.
Tham chiếu con trỏ rỗng thuần tuý
Đây là sự cố gốc kinh điển và mặc dù chỉ là một trường hợp đặc biệt của loại sự cố tiếp theo, nhưng bạn nên đề cập riêng vì sự cố này thường ít gây phiền toái nhất.
Trong ví dụ bên dưới, mặc dù hàm gặp sự cố nằm trong libc.so
, nhưng vì các hàm chuỗi chỉ hoạt động trên con trỏ được cung cấp, nên bạn có thể suy luận rằng strlen(3)
được gọi bằng con trỏ rỗng; và sự cố này sẽ trực tiếp đến tác giả của mã gọi. Trong trường hợp này, khung #01 là phương thức gọi không hợp lệ.
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)
Bạn có thể tái tạo một thực thể của loại sự cố này bằng crasher
strlen-NULL
.
Tham chiếu con trỏ rỗng địa chỉ thấp
Trong nhiều trường hợp, địa chỉ lỗi sẽ không phải là 0 mà là một số thấp khác. Đặc biệt, địa chỉ hai hoặc ba chữ số rất phổ biến, trong khi địa chỉ sáu chữ số gần như chắc chắn không phải là tham chiếu giá trị rỗng của con trỏ – điều này sẽ yêu cầu độ dời 1 MiB. Điều này thường xảy ra khi bạn có mã tham chiếu giá trị rỗng như thể đó là một cấu trúc hợp lệ. Các hàm phổ biến là fprintf(3)
(hoặc bất kỳ hàm nào khác lấy FILE*) và readdir(3)
, vì mã thường không kiểm tra được lệnh gọi fopen(3)
hoặc opendir(3)
thực sự thành công trước tiên.
Sau đây là ví dụ về 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)
Ở đây, nguyên nhân trực tiếp gây ra sự cố là pthread_mutex_lock(3)
đã cố gắng truy cập vào địa chỉ 0xc (khung 0). Tuy nhiên, việc đầu tiên mà pthread_mutex_lock
thực hiện là huỷ tham chiếu phần tử state
của pthread_mutex_t*
đã được cung cấp. Nếu xem nguồn, bạn có thể thấy phần tử đó ở độ dời 0 trong cấu trúc, cho biết rằng pthread_mutex_lock
đã được cấp con trỏ không hợp lệ 0xc. Từ khung 1, bạn có thể thấy rằng khung này được readdir
cung cấp con trỏ đó, giúp trích xuất trường mutex_
từ DIR*
được cung cấp. Khi xem xét cấu trúc đó, bạn có thể thấy mutex_
ở độ dời sizeof(int) + sizeof(size_t) + sizeof(dirent*)
vào struct DIR
, trên thiết bị 32 bit là 4 + 4 + 4 = 12 = 0xc, vì vậy bạn đã tìm thấy lỗi: readdir
được truyền con trỏ rỗng bởi phương thức gọi. Tại thời điểm này, bạn có thể dán ngăn xếp vào công cụ ngăn xếp để tìm hiểu vị trí trong logcat nơi sự cố này xảy ra.
struct DIR { int fd_; size_t available_bytes_; dirent* next_; pthread_mutex_t mutex_; dirent buff_[15]; long current_pos_; };
Trong hầu hết các trường hợp, bạn có thể bỏ qua quy trình phân tích này. Địa chỉ lỗi đủ thấp thường có nghĩa là bạn chỉ có thể bỏ qua mọi khung libc.so
trong ngăn xếp và trực tiếp buộc tội mã gọi. Nhưng không phải lúc nào cũng vậy, và đây là cách bạn trình bày một trường hợp thuyết phục.
Bạn có thể tái tạo các phiên bản của loại sự cố này bằng cách sử dụng crasher
fprintf-NULL
hoặc crasher readdir-NULL
.
Lỗi FORTIFY
Lỗi FORTIFY là một trường hợp đặc biệt của trường hợp huỷ xảy ra khi thư viện C phát hiện một vấn đề có thể dẫn đến lỗ hổng bảo mật. Nhiều hàm thư viện C được củng cố; các hàm này lấy một đối số bổ sung cho biết kích thước thực tế của vùng đệm và kiểm tra tại thời gian chạy xem thao tác bạn đang cố gắng thực hiện có thực sự phù hợp hay không. Dưới đây là ví dụ về trường hợp mã cố gắng read(fd, buf, 32)
vào một vùng đệm thực sự chỉ dài 10 byte...
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)
Bạn có thể tái tạo một thực thể của loại sự cố này bằng crasher
fortify
.
-fstack-protector phát hiện tệp xếp bị hỏng
Tuỳ chọn -fstack-protector
của trình biên dịch sẽ chèn các bước kiểm tra vào các hàm có vùng đệm trên ngăn xếp để ngăn chặn tình trạng tràn vùng đệm. Tuỳ chọn này bật theo mặc định cho mã nền tảng nhưng không bật cho ứng dụng. Khi bạn bật tuỳ chọn này, trình biên dịch sẽ thêm hướng dẫn vào phần mở đầu hàm để ghi một giá trị ngẫu nhiên ngay sau giá trị cục bộ cuối cùng trên ngăn xếp và vào phần kết thúc hàm để đọc lại giá trị đó và kiểm tra để đảm bảo giá trị đó không thay đổi. Nếu giá trị đó thay đổi, thì giá trị đó sẽ bị ghi đè bởi tình trạng tràn bộ đệm, vì vậy, phần kết sẽ gọi __stack_chk_fail
để ghi nhật ký thông báo và huỷ.
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)
Bạn có thể phân biệt loại này với các loại huỷ khác bằng sự hiện diện của __stack_chk_fail
trong dấu vết lui và thông báo huỷ cụ thể.
Bạn có thể tái tạo một thực thể của loại sự cố này bằng crasher
smash-stack
.
Seccomp SIGSYS từ một lệnh gọi hệ thống không được cho phép
Hệ thống seccomp (cụ thể là seccomp-bpf) hạn chế quyền truy cập vào các lệnh gọi hệ thống. Để biết thêm thông tin về seccomp dành cho nhà phát triển nền tảng, hãy xem bài đăng trên blog Bộ lọc seccomp trong Android O. Một luồng gọi lệnh gọi hệ thống bị hạn chế sẽ nhận được tín hiệu SIGSYS có mã SYS_SECCOMP. Số lệnh gọi hệ thống sẽ xuất hiện trong dòng nguyên nhân, cùng với cấu trúc. Xin lưu ý rằng số lệnh gọi hệ thống thay đổi tuỳ theo cấu trúc. Ví dụ: lệnh gọi hệ thống readlinkat(2)
là số 305 trên x86 nhưng là 267 trên x86-64.
Số lệnh gọi lại khác nhau trên cả arm và arm64. Vì số lệnh gọi hệ thống khác nhau giữa các cấu trúc, nên thường dễ dàng hơn khi sử dụng dấu vết ngăn xếp để tìm ra lệnh gọi hệ thống nào bị từ chối thay vì tìm số lệnh gọi hệ thống trong tiêu đề.
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)
Bạn có thể phân biệt các lệnh gọi hệ thống không được cho phép với các sự cố khác bằng sự hiện diện của SYS_SECCOMP
trên dòng tín hiệu và nội dung mô tả trên dòng nguyên nhân.
Bạn có thể tái tạo một thực thể của loại sự cố này bằng crasher
seccomp
.
Vi phạm bộ nhớ chỉ thực thi (chỉ dành cho Android 10)
Chỉ dành cho arm64 trong Android 10, các phân đoạn thực thi của tệp nhị phân và thư viện được ánh xạ vào bộ nhớ chỉ thực thi (không đọc được) dưới dạng một kỹ thuật tăng cường chống lại các cuộc tấn công tái sử dụng mã. Phương pháp giảm thiểu này tương tác không tốt với các phương pháp giảm thiểu khác và sau đó đã bị xoá.
Việc khiến mã không đọc được sẽ gây ra các lượt đọc có chủ ý và không chủ ý vào các phân đoạn bộ nhớ được đánh dấu là chỉ thực thi để gửi một SIGSEGV
có mã SEGV_ACCERR
. Điều này có thể xảy ra do lỗi, lỗ hổng, dữ liệu bị trộn lẫn với mã (chẳng hạn như nhóm ký tự), hoặc do hoạt động tự kiểm tra bộ nhớ có chủ ý.
Trình biên dịch giả định mã và dữ liệu không bị trộn lẫn, nhưng các vấn đề có thể phát sinh từ việc tập hợp viết tay. Trong nhiều trường hợp, bạn có thể khắc phục những lỗi này chỉ bằng cách di chuyển các hằng số sang phần .data
.
Nếu việc tự kiểm tra mã là hoàn toàn cần thiết trên các phần mã có thể thực thi, trước tiên, bạn nên gọi mprotect(2)
để đánh dấu mã có thể đọc được, sau đó gọi lại để đánh dấu mã không đọc được sau khi thao tác hoàn tất.
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)
Bạn có thể phân biệt các lỗi vi phạm bộ nhớ chỉ thực thi với các sự cố khác theo dòng nguyên nhân.
Bạn có thể tái tạo một thực thể của loại sự cố này bằng crasher xom
.
Lỗi do fdsan phát hiện
Trình dọn dẹp chỉ số mô tả tệp fdsan của Android giúp phát hiện các lỗi thường gặp với chỉ số mô tả tệp, chẳng hạn như sử dụng sau khi đóng và đóng hai lần. Hãy xem tài liệu về fdsan để biết thêm thông tin chi tiết về cách gỡ lỗi (và tránh) loại lỗi này.
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)
Bạn có thể phân biệt loại này với các loại huỷ khác bằng sự hiện diện của fdsan_error
trong dấu vết lui và thông báo huỷ cụ thể.
Bạn có thể tái tạo một phiên bản của loại sự cố này bằng cách sử dụng crasher fdsan_file
hoặc crasher fdsan_dir
.
Điều tra tệp kết xuất sự cố
Nếu bạn không có sự cố cụ thể nào đang điều tra ngay lúc này, thì nguồn nền tảng sẽ bao gồm một công cụ để kiểm thử debuggerd
có tên là trình tạo sự cố. Nếu mm
trong system/core/debuggerd/
, bạn sẽ nhận được cả crasher
và crasher64
trên đường dẫn (crasher64
cho phép bạn kiểm thử sự cố 64 bit). Trình gây sự cố có thể gặp sự cố theo nhiều cách thú vị dựa trên các đối số dòng lệnh mà bạn cung cấp.
Sử dụng crasher --help
để xem lựa chọn hiện được hỗ trợ.
Để giới thiệu các phần khác nhau trong tệp báo lỗi, hãy xem xét tệp báo lỗi mẫu sau:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 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 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Dòng dấu hoa thị có dấu cách sẽ hữu ích nếu bạn đang tìm kiếm nhật ký để tìm sự cố gốc. Chuỗi "*** ***" hiếm khi xuất hiện trong nhật ký, ngoại trừ khi bắt đầu một sự cố gốc.
Build fingerprint: 'Android/aosp_flounder/flounder:5.1.51/AOSP/enh08201009:eng/test-keys'
Vân tay số cho phép bạn xác định chính xác bản dựng xảy ra sự cố.
Điều này giống hệt với thuộc tính hệ thống ro.build.fingerprint
.
Revision: '0'
Bản sửa đổi này đề cập đến phần cứng thay vì phần mềm. Thuộc tính này thường không được sử dụng nhưng có thể hữu ích để giúp bạn tự động bỏ qua các lỗi được biết là do phần cứng bị lỗi. Điều này giống hệt như thuộc tính hệ thống ro.revision
.
ABI: 'arm'
ABI là một trong các arm, arm64, x86 hoặc x86-64. Điều này chủ yếu
hữu ích cho tập lệnh stack
được đề cập ở trên, để tập lệnh này biết
nên sử dụng chuỗi công cụ nào.
pid: 1656, tid: 1656, name: crasher >>> crasher <<<
Dòng này xác định luồng cụ thể trong quy trình gặp sự cố. Trong trường hợp này, đó là luồng chính của quy trình, vì vậy, mã nhận dạng quy trình và mã nhận dạng luồng khớp nhau. Tên đầu tiên là tên luồng và tên được bao quanh bởi >>> và <<< là tên quy trình. Đối với một ứng dụng, tên quy trình thường là tên gói đủ điều kiện (chẳng hạn như com.facebook.katana). Tên này rất hữu ích khi gửi lỗi hoặc tìm ứng dụng trong Google Play. pid và tid cũng có thể hữu ích trong việc tìm các dòng nhật ký có liên quan trước khi xảy ra sự cố.
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Dòng này cho bạn biết tín hiệu nào (SIGABRT) đã được nhận và thêm thông tin về cách nhận tín hiệu đó (SI_TKILL). Các tín hiệu do debuggerd
báo cáo là SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV và SIGTRAP. Các mã dành riêng cho tín hiệu sẽ khác nhau tuỳ theo tín hiệu cụ thể.
Abort message: 'some_file.c:123: some_function: assertion "false" failed'
Không phải sự cố nào cũng có dòng thông báo huỷ, nhưng các sự cố huỷ sẽ có. Thông tin này được tự động thu thập từ dòng cuối cùng của đầu ra logcat nghiêm trọng cho pid/tid này và trong trường hợp cố ý huỷ, có thể sẽ đưa ra giải thích về lý do chương trình tự huỷ.
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
Tệp kết xuất thanh ghi cho thấy nội dung của các thanh ghi CPU tại thời điểm nhận được tín hiệu. (Phần này thay đổi rất nhiều giữa các ABI.) Mức độ hữu ích của các thông tin này sẽ phụ thuộc vào sự cố chính xác.
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
Dấu vết ngược cho bạn biết vị trí của mã tại thời điểm xảy ra sự cố. Cột đầu tiên là số khung (khớp với kiểu của gdb, trong đó khung sâu nhất là 0). Các giá trị PC tương ứng với vị trí của thư viện chia sẻ thay vì địa chỉ tuyệt đối. Cột tiếp theo là tên của vùng được liên kết (thường là thư viện dùng chung hoặc tệp thực thi, nhưng có thể không phải là mã được biên dịch JIT). Cuối cùng, nếu có ký hiệu, ký hiệu tương ứng với giá trị PC sẽ hiển thị, cùng với độ dời vào ký hiệu đó tính bằng byte. Bạn có thể sử dụng hàm này cùng với objdump(1)
để tìm lệnh tập hợp tương ứng.
Đọc mốc thời gian
Tombstone written to: /data/tombstones/tombstone_06
Thông tin này cho bạn biết vị trí debuggerd
đã ghi thêm thông tin.
debuggerd
sẽ giữ tối đa 10 bia mộ, luân phiên qua các số từ 00 đến 09 và ghi đè các bia mộ hiện có nếu cần.
Tombstone chứa thông tin giống như tệp báo lỗi, cùng với một số thông tin bổ sung. Ví dụ: tệp này bao gồm các dấu vết lui cho tất cả luồng (không chỉ luồng gặp sự cố), thanh ghi dấu phẩy động, tệp kết xuất ngăn xếp thô và tệp kết xuất bộ nhớ xung quanh các địa chỉ trong thanh ghi. Quan trọng nhất là tệp này cũng bao gồm một bản đồ bộ nhớ đầy đủ (tương tự như /proc/pid/maps
). Dưới đây là ví dụ được chú thích về sự cố quy trình ARM 32 bit:
memory map: (fault address prefixed with --->) --->ab15f000-ab162fff r-x 0 4000 /system/xbin/crasher (BuildId: b9527db01b5cf8f5402f899f64b9b121)
Có hai điều cần lưu ý ở đây. Đầu tiên, dòng này có tiền tố là "--->". Các bản đồ hữu ích nhất khi sự cố của bạn không chỉ là tham chiếu giá trị rỗng của con trỏ. Nếu địa chỉ lỗi nhỏ, thì đó có thể là một số biến thể của tham chiếu giá trị rỗng. Nếu không, việc xem bản đồ xung quanh địa chỉ lỗi thường có thể cho bạn biết điều gì đã xảy ra. Một số vấn đề có thể nhận thấy khi xem bản đồ bao gồm:
- Đọc/ghi quá cuối khối bộ nhớ.
- Đọc/ghi trước khi bắt đầu một khối bộ nhớ.
- Cố gắng thực thi không phải mã.
- Chạy hết ngăn xếp.
- Cố gắng ghi vào mã (như trong ví dụ trên).
Điều thứ hai cần lưu ý là các tệp thực thi và thư viện dùng chung sẽ hiển thị BuildId (nếu có) trong Android 6.0 trở lên, nhờ đó, bạn có thể biết chính xác phiên bản mã nào đã gặp sự cố. Tệp nhị phân của nền tảng bao gồm một BuildId theo mặc định kể từ Android 6.0; NDK r12 trở lên cũng tự động truyền -Wl,--build-id
đến trình liên kết.
ab163000-ab163fff r-- 3000 1000 /system/xbin/crasher ab164000-ab164fff rw- 0 1000 f6c80000-f6d7ffff rw- 0 100000 [anon:libc_malloc]
Trên Android, vùng nhớ khối xếp không nhất thiết phải là một vùng duy nhất. Các vùng vùng nhớ khối xếp sẽ được gắn nhãn [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
Thông thường, một thư viện dùng chung có ba mục nhập liền kề. Một là có thể đọc và thực thi (mã), một là chỉ có thể đọc (dữ liệu chỉ có thể đọc) và một là có thể đọc và ghi (dữ liệu có thể thay đổi). Cột đầu tiên cho biết các dải địa chỉ cho mối liên kết, cột thứ hai cho biết các quyền (theo kiểu ls(1)
Unix thông thường), cột thứ ba cho biết độ dời vào tệp (theo hệ thập lục phân), cột thứ tư cho biết kích thước của vùng (theo hệ thập lục phân) và cột thứ năm cho biết tệp (hoặc tên vùng khác).
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]
Kể từ Android 5.0, thư viện C đặt tên cho hầu hết các vùng được ánh xạ ẩn danh để có ít vùng bí ẩn hơn.
f6fcb000-f6fccfff rw- 0 2000 [stack:5081]
Các vùng có tên [stack:tid]
là ngăn xếp cho các luồng đã cho.
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]
Việc bạn thấy [vector]
hay [vdso]
phụ thuộc vào cấu trúc. ARM sử dụng [vector]
, trong khi tất cả các cấu trúc khác sử dụng [vdso]
.