diff --git a/debuggerd/utility.c b/debuggerd/utility.c index 64e59809b..2ccf947e6 100644 --- a/debuggerd/utility.c +++ b/debuggerd/utility.c @@ -65,16 +65,10 @@ static void dump_backtrace(const ptrace_context_t* context __attribute((unused)) backtrace_symbol_t backtrace_symbols[STACK_DEPTH]; get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); for (size_t i = 0; i < frames; i++) { - const backtrace_symbol_t* symbol = &backtrace_symbols[i]; - const char* map_name = symbol->map_name ? symbol->map_name : ""; - const char* symbol_name = symbol->demangled_name ? symbol->demangled_name : symbol->name; - if (symbol_name) { - _LOG(tfd, !at_fault, " #%02d pc %08x %s (%s)\n", - (int)i, symbol->relative_pc, map_name, symbol_name); - } else { - _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", - (int)i, symbol->relative_pc, map_name); - } + char line[MAX_BACKTRACE_LINE_LENGTH]; + format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i], + line, MAX_BACKTRACE_LINE_LENGTH); + _LOG(tfd, !at_fault, " %s\n", line); } free_backtrace_symbols(backtrace_symbols, frames); } @@ -94,12 +88,23 @@ static void dump_stack_segment(const ptrace_context_t* context, int tfd, pid_t t if (symbol) { char* demangled_name = demangle_symbol_name(symbol->name); const char* symbol_name = demangled_name ? demangled_name : symbol->name; + uint32_t offset = stack_content - (mi->start + symbol->start); if (!i && label >= 0) { - _LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s (%s)\n", - label, *sp, stack_content, mi ? mi->name : "", symbol_name); + if (offset) { + _LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s (%s+%u)\n", + label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset); + } else { + _LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s (%s)\n", + label, *sp, stack_content, mi ? mi->name : "", symbol_name); + } } else { - _LOG(tfd, only_in_tombstone, " %08x %08x %s (%s)\n", - *sp, stack_content, mi ? mi->name : "", symbol_name); + if (offset) { + _LOG(tfd, only_in_tombstone, " %08x %08x %s (%s+%u)\n", + *sp, stack_content, mi ? mi->name : "", symbol_name, offset); + } else { + _LOG(tfd, only_in_tombstone, " %08x %08x %s (%s)\n", + *sp, stack_content, mi ? mi->name : "", symbol_name); + } } free(demangled_name); } else { diff --git a/include/corkscrew/backtrace.h b/include/corkscrew/backtrace.h index 157d02934..556ad04c0 100644 --- a/include/corkscrew/backtrace.h +++ b/include/corkscrew/backtrace.h @@ -41,10 +41,12 @@ typedef struct { * Describes the symbols associated with a backtrace frame. */ typedef struct { - uintptr_t relative_pc; /* relative PC offset from the start of the library, + uintptr_t relative_pc; /* relative frame PC offset from the start of the library, or the absolute PC if the library is unknown */ + uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the + library or 0 if the library is unknown */ char* map_name; /* executable or library name, or NULL if unknown */ - char* name; /* symbol name, or NULL if unknown */ + char* symbol_name; /* symbol name, or NULL if unknown */ char* demangled_name; /* demangled symbol name, or NULL if unknown */ } backtrace_symbol_t; @@ -95,6 +97,17 @@ void get_backtrace_symbols_ptrace(const ptrace_context_t* context, */ void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames); +enum { + // A hint for how big to make the line buffer for format_backtrace_line + MAX_BACKTRACE_LINE_LENGTH = 800, +}; + +/** + * Formats a line from a backtrace as a zero-terminated string into the specified buffer. + */ +void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame, + const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize); + #ifdef __cplusplus } #endif diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c index cf9a5ab32..5b9116487 100644 --- a/libcorkscrew/arch-arm/backtrace-arm.c +++ b/libcorkscrew/arch-arm/backtrace-arm.c @@ -146,6 +146,7 @@ static uintptr_t get_exception_handler(const memory_t* memory, } uintptr_t handler = 0; + int32_t handler_index = -1; if (exidx_start) { uint32_t low = 0; uint32_t high = exidx_size; @@ -153,10 +154,12 @@ static uintptr_t get_exception_handler(const memory_t* memory, uint32_t index = (low + high) / 2; uintptr_t entry = exidx_start + index * 8; uint32_t entry_prel_pc; + ALOGV("XXX low=%u, high=%u, index=%u", low, high, index); if (!try_get_word(memory, entry, &entry_prel_pc)) { break; } uintptr_t entry_pc = prel_to_absolute(entry, entry_prel_pc); + ALOGV("XXX entry_pc=0x%08x", entry_pc); if (pc < entry_pc) { high = index; continue; @@ -168,6 +171,7 @@ static uintptr_t get_exception_handler(const memory_t* memory, break; } uintptr_t next_entry_pc = prel_to_absolute(next_entry, next_entry_prel_pc); + ALOGV("XXX next_entry_pc=0x%08x", next_entry_pc); if (pc >= next_entry_pc) { low = index + 1; continue; @@ -184,17 +188,18 @@ static uintptr_t get_exception_handler(const memory_t* memory, } else if (entry_handler != EXIDX_CANTUNWIND) { handler = prel_to_absolute(entry_handler_ptr, entry_handler); } + handler_index = index; break; } } if (mi) { ALOGV("get_exception_handler: pc=0x%08x, module='%s', module_start=0x%08x, " - "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x", - pc, mi->name, mi->start, exidx_start, exidx_size, handler); + "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d", + pc, mi->name, mi->start, exidx_start, exidx_size, handler, handler_index); } else { ALOGV("get_exception_handler: pc=0x%08x, " - "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x", - pc, exidx_start, exidx_size, handler); + "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d", + pc, exidx_start, exidx_size, handler, handler_index); } return handler; } @@ -464,11 +469,10 @@ uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) { * 18896: 4798 blx r3 * 18898: b001 add sp, #4 */ - pc &= ~1; uint16_t prev1, prev2; - if (try_get_half_word(memory, pc - 4, &prev1) + if (try_get_half_word(memory, pc - 5, &prev1) && ((prev1 & 0xf000) == 0xf000) - && try_get_half_word(memory, pc - 2, &prev2) + && try_get_half_word(memory, pc - 3, &prev2) && ((prev2 & 0xe000) == 0xe000)) { pc -= 4; // long offset } else { diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c index 857b7417d..fa215742b 100644 --- a/libcorkscrew/backtrace.c +++ b/libcorkscrew/backtrace.c @@ -213,8 +213,9 @@ ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context, static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) { symbol->relative_pc = pc; + symbol->relative_symbol_addr = 0; symbol->map_name = NULL; - symbol->name = NULL; + symbol->symbol_name = NULL; symbol->demangled_name = NULL; } @@ -235,8 +236,10 @@ void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames, #if HAVE_DLADDR Dl_info info; if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) { - symbol->name = strdup(info.dli_sname); - symbol->demangled_name = demangle_symbol_name(symbol->name); + symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr + - (uintptr_t)info.dli_fbase; + symbol->symbol_name = strdup(info.dli_sname); + symbol->demangled_name = demangle_symbol_name(symbol->symbol_name); } #endif } @@ -262,8 +265,9 @@ void get_backtrace_symbols_ptrace(const ptrace_context_t* context, } } if (s) { - symbol->name = strdup(s->name); - symbol->demangled_name = demangle_symbol_name(symbol->name); + symbol->relative_symbol_addr = s->start; + symbol->symbol_name = strdup(s->name); + symbol->demangled_name = demangle_symbol_name(symbol->symbol_name); } } } @@ -272,8 +276,30 @@ void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames for (size_t i = 0; i < frames; i++) { backtrace_symbol_t* symbol = &backtrace_symbols[i]; free(symbol->map_name); - free(symbol->name); + free(symbol->symbol_name); free(symbol->demangled_name); init_backtrace_symbol(symbol, 0); } } + +void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame, + const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) { + const char* mapName = symbol->map_name ? symbol->map_name : ""; + const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name; + size_t fieldWidth = (bufferSize - 80) / 2; + if (symbolName) { + uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr; + if (pc_offset) { + snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s+%u)", + frameNumber, symbol->relative_pc, fieldWidth, mapName, + fieldWidth, symbolName, pc_offset); + } else { + snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s)", + frameNumber, symbol->relative_pc, fieldWidth, mapName, + fieldWidth, symbolName); + } + } else { + snprintf(buffer, bufferSize, "#%02d pc %08x %.*s", + frameNumber, symbol->relative_pc, fieldWidth, mapName); + } +} diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c index 8257c7737..1b97180c4 100644 --- a/libcorkscrew/symbol_table.c +++ b/libcorkscrew/symbol_table.c @@ -47,6 +47,7 @@ static int bcompar(const void *key, const void *element) { symbol_table_t* load_symbol_table(const char *filename) { symbol_table_t* table = NULL; + ALOGV("Loading symbol table from '%s'.", filename); int fd = open(filename, O_RDONLY); if (fd < 0) { @@ -154,6 +155,9 @@ symbol_table_t* load_symbol_table(const char *filename) { table->symbols[symbol_index].name = strdup(dynstr + dynsyms[i].st_name); table->symbols[symbol_index].start = dynsyms[i].st_value; table->symbols[symbol_index].end = dynsyms[i].st_value + dynsyms[i].st_size; + ALOGV(" [%d] '%s' 0x%08x-0x%08x (DYNAMIC)", + symbol_index, table->symbols[symbol_index].name, + table->symbols[symbol_index].start, table->symbols[symbol_index].end); symbol_index += 1; } } @@ -169,6 +173,9 @@ symbol_table_t* load_symbol_table(const char *filename) { table->symbols[symbol_index].name = strdup(str + syms[i].st_name); table->symbols[symbol_index].start = syms[i].st_value; table->symbols[symbol_index].end = syms[i].st_value + syms[i].st_size; + ALOGV(" [%d] '%s' 0x%08x-0x%08x", + symbol_index, table->symbols[symbol_index].name, + table->symbols[symbol_index].start, table->symbols[symbol_index].end); symbol_index += 1; } }