diff options
Diffstat (limited to 'debuggerd')
-rw-r--r-- | debuggerd/Android.mk | 13 | ||||
-rw-r--r-- | debuggerd/arm/machine.cpp | 59 | ||||
-rw-r--r-- | debuggerd/arm/vfp.S (renamed from debuggerd/vfp.S) | 0 | ||||
-rw-r--r-- | debuggerd/arm64/crashglue.S | 47 | ||||
-rw-r--r-- | debuggerd/arm64/machine.cpp | 123 | ||||
-rw-r--r-- | debuggerd/arm64/vfp.S | 42 | ||||
-rw-r--r-- | debuggerd/crasher.c | 13 | ||||
-rw-r--r-- | debuggerd/debuggerd.cpp | 3 | ||||
-rw-r--r-- | debuggerd/mips/machine.cpp | 55 | ||||
-rwxr-xr-x[-rw-r--r--] | debuggerd/tombstone.cpp | 83 | ||||
-rw-r--r-- | debuggerd/utility.cpp | 121 | ||||
-rw-r--r-- | debuggerd/utility.h | 4 | ||||
-rw-r--r-- | debuggerd/x86_64/crashglue.S | 15 | ||||
-rwxr-xr-x | debuggerd/x86_64/machine.cpp | 51 |
14 files changed, 424 insertions, 205 deletions
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index 422a86a..e0a2d96 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -1,7 +1,5 @@ # Copyright 2005 The Android Open Source Project -ifneq ($(filter arm mips x86,$(TARGET_ARCH)),) - LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -19,8 +17,13 @@ LOCAL_CFLAGS := \ -Wall \ -Wno-array-bounds \ -Werror \ + -Wno-unused-parameter \ -LOCAL_MODULE := debuggerd +ifeq ($(TARGET_IS_64_BIT),true) + LOCAL_MODULE := debuggerd64 +else + LOCAL_MODULE := debuggerd +endif ifeq ($(ARCH_ARM_HAVE_VFP),true) LOCAL_CFLAGS += -DWITH_VFP @@ -59,12 +62,10 @@ ifeq ($(ARCH_ARM_HAVE_VFP_D32),true) LOCAL_CFLAGS += -DWITH_VFP_D32 endif # ARCH_ARM_HAVE_VFP_D32 -LOCAL_SRC_FILES := vfp-crasher.c vfp.S +LOCAL_SRC_FILES := vfp-crasher.c $(TARGET_ARCH)/vfp.S LOCAL_MODULE := vfp-crasher LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := optional LOCAL_SHARED_LIBRARIES := libcutils liblog libc include $(BUILD_EXECUTABLE) endif # ARCH_ARM_HAVE_VFP == true - -endif # arm or x86 in TARGET_ARCH diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp index 3fba6db..fd2f69b 100644 --- a/debuggerd/arm/machine.cpp +++ b/debuggerd/arm/machine.cpp @@ -38,65 +38,6 @@ #endif #endif -static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { - char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45 - char ascii_buffer[32]; // actual 16 + 1 == 17 - uintptr_t p, end; - - p = addr & ~3; - p -= 32; - if (p > addr) { - // catch underflow - p = 0; - } - // Dump more memory content for the crashing thread. - end = p + 256; - // catch overflow; 'end - p' has to be multiples of 16 - while (end < p) - end -= 16; - - // Dump the code around PC as: - // addr contents ascii - // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q - // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... - while (p < end) { - char* asc_out = ascii_buffer; - - sprintf(code_buffer, "%08x ", p); - - int i; - for (i = 0; i < 4; i++) { - // If we see (data == -1 && errno != 0), we know that the ptrace - // call failed, probably because we're dumping memory in an - // unmapped or inaccessible page. I don't know if there's - // value in making that explicit in the output -- it likely - // just complicates parsing and clarifies nothing for the - // enlightened reader. - long data = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(p), NULL); - sprintf(code_buffer + strlen(code_buffer), "%08lx ", data); - - // Enable the following code blob to dump ASCII values -#if 0 - int j; - for (j = 0; j < 4; j++) { - // Our isprint() allows high-ASCII characters that display - // differently (often badly) in different viewers, so we - // just use a simpler test. - char val = (data >> (j*8)) & 0xff; - if (val >= 0x20 && val < 0x7f) { - *asc_out++ = val; - } else { - *asc_out++ = '.'; - } - } -#endif - p += 4; - } - *asc_out = '\0'; - _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer); - } -} - // If configured to do so, dump memory around *all* registers // for the crashing thread. void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { diff --git a/debuggerd/vfp.S b/debuggerd/arm/vfp.S index 9744f6f..9744f6f 100644 --- a/debuggerd/vfp.S +++ b/debuggerd/arm/vfp.S diff --git a/debuggerd/arm64/crashglue.S b/debuggerd/arm64/crashglue.S new file mode 100644 index 0000000..b06b67c --- /dev/null +++ b/debuggerd/arm64/crashglue.S @@ -0,0 +1,47 @@ +.globl crash1 +.type crash1, %function +.globl crashnostack +.type crashnostack, %function + +crash1: + ldr x0, =0xa5a50000 + ldr x1, =0xa5a50001 + ldr x2, =0xa5a50002 + ldr x3, =0xa5a50003 + ldr x4, =0xa5a50004 + ldr x5, =0xa5a50005 + ldr x6, =0xa5a50006 + ldr x7, =0xa5a50007 + ldr x8, =0xa5a50008 + ldr x9, =0xa5a50009 + ldr x10, =0xa5a50010 + ldr x11, =0xa5a50011 + ldr x12, =0xa5a50012 + ldr x13, =0xa5a50013 + ldr x14, =0xa5a50014 + ldr x15, =0xa5a50015 + ldr x16, =0xa5a50016 + ldr x17, =0xa5a50017 + ldr x18, =0xa5a50018 + ldr x19, =0xa5a50019 + ldr x20, =0xa5a50020 + ldr x21, =0xa5a50021 + ldr x22, =0xa5a50022 + ldr x23, =0xa5a50023 + ldr x24, =0xa5a50024 + ldr x25, =0xa5a50025 + ldr x26, =0xa5a50026 + ldr x27, =0xa5a50027 + ldr x28, =0xa5a50028 + ldr x29, =0xa5a50029 + + mov x30, xzr + ldr x30, [x30] + b . + + +crashnostack: + mov x0, xzr + add sp, x0, xzr + ldr x0, [x0] + b . diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp new file mode 100644 index 0000000..7159228 --- /dev/null +++ b/debuggerd/arm64/machine.cpp @@ -0,0 +1,123 @@ +/* + * + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/user.h> +#include <sys/uio.h> +#include <linux/elf.h> + +#include "../utility.h" +#include "../machine.h" + +/* enable to dump memory pointed to by every register */ +#define DUMP_MEMORY_FOR_ALL_REGISTERS 1 + +/* + * If configured to do so, dump memory around *all* registers + * for the crashing thread. + */ +void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { + struct user_pt_regs regs; + struct iovec io; + io.iov_base = ®s; + io.iov_len = sizeof(regs); + + if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) { + _LOG(log, scope_flags, "%s: ptrace failed to get registers: %s\n", + __func__, strerror(errno)); + return; + } + + if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { + for (int reg = 0; reg < 31; reg++) { + uintptr_t addr = regs.regs[reg]; + + /* + * Don't bother if it looks like a small int or ~= null, or if + * it's in the kernel area. + */ + if (addr < 4096 || addr >= (1UL<<63)) { + continue; + } + + _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near x%d:\n", reg); + dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); + } + } + + _LOG(log, scope_flags, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)regs.pc, scope_flags); + + if (regs.pc != regs.sp) { + _LOG(log, scope_flags, "\ncode around sp:\n"); + dump_memory(log, tid, (uintptr_t)regs.sp, scope_flags); + } +} + +void dump_registers(log_t* log, pid_t tid, int scope_flags) +{ + struct user_pt_regs r; + struct iovec io; + io.iov_base = &r; + io.iov_len = sizeof(r); + + bool only_in_tombstone = !IS_AT_FAULT(scope_flags); + + if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) { + _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno)); + return; + } + + for (int i = 0; i < 28; i += 4) { + _LOG(log, scope_flags, " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n", + i, (uint64_t)r.regs[i], + i+1, (uint64_t)r.regs[i+1], + i+2, (uint64_t)r.regs[i+2], + i+3, (uint64_t)r.regs[i+3]); + } + + _LOG(log, scope_flags, " x28 %016lx x29 %016lx x30 %016lx\n", + (uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]); + + _LOG(log, scope_flags, " sp %016lx pc %016lx\n", + (uint64_t)r.sp, (uint64_t)r.pc); + + + struct user_fpsimd_state f; + io.iov_base = &f; + io.iov_len = sizeof(f); + + if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) { + _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno)); + return; + } + + for (int i = 0; i < 32; i += 4) { + _LOG(log, scope_flags, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n", + i, (uint64_t)f.vregs[i], + i+1, (uint64_t)f.vregs[i+1], + i+2, (uint64_t)f.vregs[i+2], + i+3, (uint64_t)f.vregs[i+3]); + } +} diff --git a/debuggerd/arm64/vfp.S b/debuggerd/arm64/vfp.S new file mode 100644 index 0000000..bf12c22 --- /dev/null +++ b/debuggerd/arm64/vfp.S @@ -0,0 +1,42 @@ + .text + .align 2 + .global crash + .type crash, %function +crash: + fmov d0, XZR + fmov d1, 1.0 + fmov d2, 2.0 + fmov d3, 3.0 + fmov d4, 4.0 + fmov d5, 5.0 + fmov d6, 6.0 + fmov d7, 7.0 + fmov d8, 8.0 + fmov d9, 9.0 + fmov d10, 10.0 + fmov d11, 11.0 + fmov d12, 12.0 + fmov d13, 13.0 + fmov d14, 14.0 + fmov d15, 15.0 + fmov d16, 16.0 + fmov d17, 17.0 + fmov d18, 18.0 + fmov d19, 19.0 + fmov d20, 20.0 + fmov d21, 21.0 + fmov d22, 22.0 + fmov d23, 23.0 + fmov d24, 24.0 + fmov d25, 25.0 + fmov d26, 26.0 + fmov d27, 27.0 + fmov d28, 28.0 + fmov d29, 29.0 + fmov d30, 30.0 + fmov d31, 31.0 + + mov x0, xzr + str x0, [x0] + br x30 + diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c index 5ecb1a5..0033948 100644 --- a/debuggerd/crasher.c +++ b/debuggerd/crasher.c @@ -23,19 +23,6 @@ void crash1(void); void crashnostack(void); static int do_action(const char* arg); -static void debuggerd_connect() -{ - char tmp[1]; - int s; - sprintf(tmp, "%d", gettid()); - s = socket_local_client("android:debuggerd", - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - if(s >= 0) { - read(s, tmp, 1); - close(s); - } -} - static void maybeabort() { if(time(0) != 42) { abort(); diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index de8ba9d..c39aaf6 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -205,7 +205,8 @@ static int read_request(int fd, debugger_request_t* out_request) { return -1; } if (status == sizeof(debugger_msg_t)) { - XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address); + XLOG("crash request of size %d abort_msg_address=0x%" PRIPTR "\n", + status, msg.abort_msg_address); } else { LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid); return -1; diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp index d1a7f2d..7b4e29e 100644 --- a/debuggerd/mips/machine.cpp +++ b/debuggerd/mips/machine.cpp @@ -34,61 +34,6 @@ #define R(x) (static_cast<unsigned int>(x)) -static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { - char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45 - char ascii_buffer[32]; // actual 16 + 1 == 17 - uintptr_t p, end; - - p = addr & ~3; - p -= 32; - if (p > addr) { - // catch underflow - p = 0; - } - end = p + 80; - // catch overflow; 'end - p' has to be multiples of 16 - while (end < p) - end -= 16; - - // Dump the code around PC as: - // addr contents ascii - // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q - // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... - while (p < end) { - char* asc_out = ascii_buffer; - - sprintf(code_buffer, "%08x ", p); - - int i; - for (i = 0; i < 4; i++) { - // If we see (data == -1 && errno != 0), we know that the ptrace - // call failed, probably because we're dumping memory in an - // unmapped or inaccessible page. I don't know if there's - // value in making that explicit in the output -- it likely - // just complicates parsing and clarifies nothing for the - // enlightened reader. - long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL); - sprintf(code_buffer + strlen(code_buffer), "%08lx ", data); - - int j; - for (j = 0; j < 4; j++) { - // Our isprint() allows high-ASCII characters that display - // differently (often badly) in different viewers, so we - // just use a simpler test. - char val = (data >> (j*8)) & 0xff; - if (val >= 0x20 && val < 0x7f) { - *asc_out++ = val; - } else { - *asc_out++ = '.'; - } - } - p += 4; - } - *asc_out = '\0'; - _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer); - } -} - // If configured to do so, dump memory around *all* registers // for the crashing thread. void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index 11e9af5..c630020 100644..100755 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp @@ -14,18 +14,20 @@ * limitations under the License. */ +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <signal.h> #include <stddef.h> +#include <stdio.h> #include <stdlib.h> -#include <signal.h> #include <string.h> -#include <stdio.h> -#include <fcntl.h> -#include <errno.h> -#include <dirent.h> #include <time.h> #include <sys/ptrace.h> +#include <sys/socket.h> #include <sys/stat.h> -#include <inttypes.h> +#include <sys/un.h> #include <private/android_filesystem_config.h> @@ -36,9 +38,6 @@ #include <backtrace/Backtrace.h> #include <backtrace/BacktraceMap.h> -#include <sys/socket.h> -#include <linux/un.h> - #include <selinux/android.h> #include <UniquePtr.h> @@ -51,6 +50,7 @@ #define MAX_TOMBSTONES 10 #define TOMBSTONE_DIR "/data/tombstones" +#define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d") // Must match the path defined in NativeCrashListener.java #define NCRASH_SOCKET_PATH "/data/system/ndebugsocket" @@ -60,7 +60,6 @@ typeof(y) __dummy2; \ (void)(&__dummy1 == &__dummy2); } - static bool signal_has_address(int sig) { switch (sig) { case SIGILL: @@ -180,9 +179,9 @@ static void dump_fault_addr(log_t* log, pid_t tid, int sig) { if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){ _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno)); } else if (signal_has_address(sig)) { - _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %0*" PRIxPTR "\n", + _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %" PRIPTR "\n", sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code), - sizeof(uintptr_t)*2, reinterpret_cast<uintptr_t>(si.si_addr)); + reinterpret_cast<uintptr_t>(si.si_addr)); } else { _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n", sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code)); @@ -227,7 +226,7 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) static void dump_stack_segment( Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) { for (size_t i = 0; i < words; i++) { - uint32_t stack_content; + word_t stack_content; if (!backtrace->ReadWord(*sp, &stack_content)) { break; } @@ -244,32 +243,32 @@ static void dump_stack_segment( if (!func_name.empty()) { if (!i && label >= 0) { if (offset) { - _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n", + _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", label, *sp, stack_content, map_name, func_name.c_str(), offset); } else { - _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n", + _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n", label, *sp, stack_content, map_name, func_name.c_str()); } } else { if (offset) { - _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n", + _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", *sp, stack_content, map_name, func_name.c_str(), offset); } else { - _LOG(log, scope_flags, " %08x %08x %s (%s)\n", + _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s)\n", *sp, stack_content, map_name, func_name.c_str()); } } } else { if (!i && label >= 0) { - _LOG(log, scope_flags, " #%02d %08x %08x %s\n", + _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s\n", label, *sp, stack_content, map_name); } else { - _LOG(log, scope_flags, " %08x %08x %s\n", + _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s\n", *sp, stack_content, map_name); } } - *sp += sizeof(uint32_t); + *sp += sizeof(word_t); } } @@ -292,7 +291,7 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) { scope_flags |= SCOPE_SENSITIVE; // Dump a few words before the first frame. - uintptr_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(uint32_t); + word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t); dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1); // Dump a few words from all successive frames. @@ -312,7 +311,7 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) { _LOG(log, scope_flags, " ........ ........\n"); } } else { - size_t words = frame->stack_size / sizeof(uint32_t); + size_t words = frame->stack_size / sizeof(word_t); if (words == 0) { words = 1; } else if (words > STACK_WORDS) { @@ -335,7 +334,7 @@ static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) { if (map != NULL) { - _LOG(log, scope_flags, " %08x-%08x %c%c%c %s\n", map->start, map->end, + _LOG(log, scope_flags, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end, (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-', (map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str()); } else { @@ -361,7 +360,7 @@ static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope return; } - _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIxPTR ":\n", + _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIPTR ":\n", reinterpret_cast<uintptr_t>(si.si_addr)); // Search for a match, or for a hole where the match would be. The list @@ -574,24 +573,15 @@ static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t addre memset(msg, 0, sizeof(msg)); char* p = &msg[0]; while (p < &msg[sizeof(msg)]) { - uint32_t data; + word_t data; + size_t len = sizeof(word_t); if (!backtrace->ReadWord(address, &data)) { break; } - address += sizeof(uint32_t); + address += sizeof(word_t); - if ((*p++ = (data >> 0) & 0xff) == 0) { - break; - } - if ((*p++ = (data >> 8) & 0xff) == 0) { - break; - } - if ((*p++ = (data >> 16) & 0xff) == 0) { - break; - } - if ((*p++ = (data >> 24) & 0xff) == 0) { - break; - } + while (len > 0 && (*p++ = (data >> (sizeof(word_t) - len) * 8) & 0xff) != 0) + len--; } msg[sizeof(msg) - 1] = '\0'; @@ -663,7 +653,11 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a // // Returns the path of the tombstone file, allocated using malloc(). Caller must free() it. static char* find_and_open_tombstone(int* fd) { +#ifdef __aarch64__ + long mtime = LONG_MAX; +#else unsigned long mtime = ULONG_MAX; +#endif struct stat sb; // XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought @@ -675,7 +669,7 @@ static char* find_and_open_tombstone(int* fd) { char path[128]; int oldest = 0; for (int i = 0; i < MAX_TOMBSTONES; i++) { - snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i); + snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i); if (!stat(path, &sb)) { if (sb.st_mtime < mtime) { @@ -696,7 +690,7 @@ static char* find_and_open_tombstone(int* fd) { } // we didn't find an available file, so we clobber the oldest one - snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest); + snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest); *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (*fd < 0) { LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno)); @@ -739,8 +733,13 @@ static int activity_manager_connect() { char* engrave_tombstone( pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address, bool dump_sibling_threads, bool quiet, bool* detach_failed, int* total_sleep_time_usec) { - mkdir(TOMBSTONE_DIR, 0755); - chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM); + if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) { + LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno)); + } + + if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) { + LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno)); + } if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) { *detach_failed = false; diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp index 35f061e..9b20914 100644 --- a/debuggerd/utility.cpp +++ b/debuggerd/utility.cpp @@ -14,19 +14,17 @@ * limitations under the License. */ -#include <stddef.h> -#include <stdio.h> -#include <string.h> +#include "utility.h" + #include <errno.h> -#include <unistd.h> #include <signal.h> -#include <log/logd.h> +#include <string.h> +#include <unistd.h> #include <sys/ptrace.h> #include <sys/wait.h> -#include <arpa/inet.h> -#include <assert.h> -#include "utility.h" +#include <backtrace/Backtrace.h> +#include <log/logd.h> const int sleep_time_usec = 50000; // 0.05 seconds const int max_total_sleep_usec = 10000000; // 10 seconds @@ -34,7 +32,7 @@ const int max_total_sleep_usec = 10000000; // 10 seconds static int write_to_am(int fd, const char* buf, int len) { int to_write = len; while (to_write > 0) { - int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) ); + int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write)); if (written < 0) { // hard failure LOG("AM write failure (%d / %s)\n", errno, strerror(errno)); @@ -46,34 +44,28 @@ static int write_to_am(int fd, const char* buf, int len) { } void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) { - char buf[512]; - bool want_tfd_write; - bool want_log_write; - bool want_amfd_write; - int len = 0; + bool want_tfd_write = log && log->tfd >= 0; + bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet); + bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0; + char buf[512]; va_list ap; va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); - // where is the information going to go? - want_tfd_write = log && log->tfd >= 0; - want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet); - want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0; - - // if we're going to need the literal string, generate it once here - if (want_tfd_write || want_amfd_write) { - vsnprintf(buf, sizeof(buf), fmt, ap); - len = strlen(buf); + size_t len = strlen(buf); + if (len <= 0) { + return; } if (want_tfd_write) { - write(log->tfd, buf, len); + TEMP_FAILURE_RETRY(write(log->tfd, buf, len)); } if (want_log_write) { - // whatever goes to logcat also goes to the Activity Manager - __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap); - if (want_amfd_write && len > 0) { + __android_log_write(ANDROID_LOG_INFO, "DEBUG", buf); + if (want_amfd_write) { int written = write_to_am(log->amfd, buf, len); if (written <= 0) { // timeout or other failure on write; stop informing the activity manager @@ -81,7 +73,6 @@ void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) { } } } - va_end(ap); } int wait_for_signal(pid_t tid, int* total_sleep_time_usec) { @@ -127,3 +118,77 @@ void wait_for_stop(pid_t tid, int* total_sleep_time_usec) { *total_sleep_time_usec += sleep_time_usec; } } + +#if defined (__mips__) +#define DUMP_MEMORY_AS_ASCII 1 +#else +#define DUMP_MEMORY_AS_ASCII 0 +#endif + +void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { + char code_buffer[64]; + char ascii_buffer[32]; + uintptr_t p, end; + + p = addr & ~(sizeof(long) - 1); + /* Dump 32 bytes before addr */ + p -= 32; + if (p > addr) { + /* catch underflow */ + p = 0; + } + /* Dump 256 bytes */ + end = p + 256; + /* catch overflow; 'end - p' has to be multiples of 16 */ + while (end < p) { + end -= 16; + } + + /* Dump the code around PC as: + * addr contents ascii + * 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q + * 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p...... + * On 32-bit machines, there are still 16 bytes per line but addresses and + * words are of course presented differently. + */ + while (p < end) { + char* asc_out = ascii_buffer; + + int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p); + + for (size_t i = 0; i < 16/sizeof(long); i++) { + long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL); + if (data == -1 && errno != 0) { + // ptrace failed, probably because we're dumping memory in an + // unmapped or inaccessible page. +#ifdef __LP64__ + len += sprintf(code_buffer + len, "---------------- "); +#else + len += sprintf(code_buffer + len, "-------- "); +#endif + } else { + len += sprintf(code_buffer + len, "%" PRIPTR " ", + static_cast<uintptr_t>(data)); + } + +#if DUMP_MEMORY_AS_ASCII + for (size_t j = 0; j < sizeof(long); j++) { + /* + * Our isprint() allows high-ASCII characters that display + * differently (often badly) in different viewers, so we + * just use a simpler test. + */ + char val = (data >> (j*8)) & 0xff; + if (val >= 0x20 && val < 0x7f) { + *asc_out++ = val; + } else { + *asc_out++ = '.'; + } + } +#endif + p += sizeof(long); + } + *asc_out = '\0'; + _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer); + } +} diff --git a/debuggerd/utility.h b/debuggerd/utility.h index 1f006ed..0f88605 100644 --- a/debuggerd/utility.h +++ b/debuggerd/utility.h @@ -18,8 +18,8 @@ #ifndef _DEBUGGERD_UTILITY_H #define _DEBUGGERD_UTILITY_H -#include <stddef.h> #include <stdbool.h> +#include <sys/types.h> typedef struct { /* tombstone file descriptor */ @@ -63,4 +63,6 @@ void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) int wait_for_signal(pid_t tid, int* total_sleep_time_usec); void wait_for_stop(pid_t tid, int* total_sleep_time_usec); +void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags); + #endif // _DEBUGGERD_UTILITY_H diff --git a/debuggerd/x86_64/crashglue.S b/debuggerd/x86_64/crashglue.S new file mode 100644 index 0000000..4d2a5c0 --- /dev/null +++ b/debuggerd/x86_64/crashglue.S @@ -0,0 +1,15 @@ +.globl crash1 +.globl crashnostack + +crash1: + movl $0xa5a50000, %eax + movl $0xa5a50001, %ebx + movl $0xa5a50002, %ecx + + movl $0, %edx + jmp *%rdx + + +crashnostack: + movl $0, %ebp + jmp *%rbp diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp new file mode 100755 index 0000000..406851a --- /dev/null +++ b/debuggerd/x86_64/machine.cpp @@ -0,0 +1,51 @@ +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stddef.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/user.h> + +#include "../utility.h" +#include "../machine.h" + +void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { +} + +void dump_registers(log_t* log, pid_t tid, int scope_flags) { + struct user_regs_struct r; + if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) { + _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); + return; + } + _LOG(log, scope_flags, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n", + r.rax, r.rbx, r.rcx, r.rdx); + _LOG(log, scope_flags, " rsi %016lx rdi %016lx\n", + r.rsi, r.rdi); + _LOG(log, scope_flags, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n", + r.r8, r.r9, r.r10, r.r11); + _LOG(log, scope_flags, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n", + r.r12, r.r13, r.r14, r.r15); + _LOG(log, scope_flags, " cs %016lx ss %016lx\n", + r.cs, r.ss); + _LOG(log, scope_flags, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n", + r.rip, r.rbp, r.rsp, r.eflags); +} |