Skip to content

Commit 19b39f3

Browse files
author
Jeff Brown
committed
Improve backtrace formatting.
Show the symbol offset, when available. Centralized formatting of native stack traces in libcorkscrew. It's handy for automated tools if all stacks look the same. Since we already made them all look them same, we might as well do the formatting in just one place. Do not strip the Thumb bit on ARM. This fixes an off-by-one issue that could happen when resolving a PC that was at the very beginning of a Thumb function, since the symbol table would have the Thumb bit set but since we stripped the bit from our PC, we would be looking for an address one byte before the one listed in the symbol table. It's also quite useful to see whether a given function is executing in Thumb mode just by glancing at the PC. Change-Id: Icaa29add85ce0bcafe24d5ce2098e138d809e2ab
1 parent de8b136 commit 19b39f3

File tree

5 files changed

+84
-29
lines changed

5 files changed

+84
-29
lines changed

debuggerd/utility.c

+19-14
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,10 @@ static void dump_backtrace(const ptrace_context_t* context __attribute((unused))
6565
backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
6666
get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
6767
for (size_t i = 0; i < frames; i++) {
68-
const backtrace_symbol_t* symbol = &backtrace_symbols[i];
69-
const char* map_name = symbol->map_name ? symbol->map_name : "<unknown>";
70-
const char* symbol_name = symbol->demangled_name ? symbol->demangled_name : symbol->name;
71-
if (symbol_name) {
72-
_LOG(tfd, !at_fault, " #%02d pc %08x %s (%s)\n",
73-
(int)i, symbol->relative_pc, map_name, symbol_name);
74-
} else {
75-
_LOG(tfd, !at_fault, " #%02d pc %08x %s\n",
76-
(int)i, symbol->relative_pc, map_name);
77-
}
68+
char line[MAX_BACKTRACE_LINE_LENGTH];
69+
format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
70+
line, MAX_BACKTRACE_LINE_LENGTH);
71+
_LOG(tfd, !at_fault, " %s\n", line);
7872
}
7973
free_backtrace_symbols(backtrace_symbols, frames);
8074
}
@@ -94,12 +88,23 @@ static void dump_stack_segment(const ptrace_context_t* context, int tfd, pid_t t
9488
if (symbol) {
9589
char* demangled_name = demangle_symbol_name(symbol->name);
9690
const char* symbol_name = demangled_name ? demangled_name : symbol->name;
91+
uint32_t offset = stack_content - (mi->start + symbol->start);
9792
if (!i && label >= 0) {
98-
_LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s (%s)\n",
99-
label, *sp, stack_content, mi ? mi->name : "", symbol_name);
93+
if (offset) {
94+
_LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s (%s+%u)\n",
95+
label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
96+
} else {
97+
_LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s (%s)\n",
98+
label, *sp, stack_content, mi ? mi->name : "", symbol_name);
99+
}
100100
} else {
101-
_LOG(tfd, only_in_tombstone, " %08x %08x %s (%s)\n",
102-
*sp, stack_content, mi ? mi->name : "", symbol_name);
101+
if (offset) {
102+
_LOG(tfd, only_in_tombstone, " %08x %08x %s (%s+%u)\n",
103+
*sp, stack_content, mi ? mi->name : "", symbol_name, offset);
104+
} else {
105+
_LOG(tfd, only_in_tombstone, " %08x %08x %s (%s)\n",
106+
*sp, stack_content, mi ? mi->name : "", symbol_name);
107+
}
103108
}
104109
free(demangled_name);
105110
} else {

include/corkscrew/backtrace.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ typedef struct {
4141
* Describes the symbols associated with a backtrace frame.
4242
*/
4343
typedef struct {
44-
uintptr_t relative_pc; /* relative PC offset from the start of the library,
44+
uintptr_t relative_pc; /* relative frame PC offset from the start of the library,
4545
or the absolute PC if the library is unknown */
46+
uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the
47+
library or 0 if the library is unknown */
4648
char* map_name; /* executable or library name, or NULL if unknown */
47-
char* name; /* symbol name, or NULL if unknown */
49+
char* symbol_name; /* symbol name, or NULL if unknown */
4850
char* demangled_name; /* demangled symbol name, or NULL if unknown */
4951
} backtrace_symbol_t;
5052

@@ -95,6 +97,17 @@ void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
9597
*/
9698
void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames);
9799

100+
enum {
101+
// A hint for how big to make the line buffer for format_backtrace_line
102+
MAX_BACKTRACE_LINE_LENGTH = 800,
103+
};
104+
105+
/**
106+
* Formats a line from a backtrace as a zero-terminated string into the specified buffer.
107+
*/
108+
void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame,
109+
const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize);
110+
98111
#ifdef __cplusplus
99112
}
100113
#endif

libcorkscrew/arch-arm/backtrace-arm.c

+11-7
Original file line numberDiff line numberDiff line change
@@ -146,17 +146,20 @@ static uintptr_t get_exception_handler(const memory_t* memory,
146146
}
147147

148148
uintptr_t handler = 0;
149+
int32_t handler_index = -1;
149150
if (exidx_start) {
150151
uint32_t low = 0;
151152
uint32_t high = exidx_size;
152153
while (low < high) {
153154
uint32_t index = (low + high) / 2;
154155
uintptr_t entry = exidx_start + index * 8;
155156
uint32_t entry_prel_pc;
157+
ALOGV("XXX low=%u, high=%u, index=%u", low, high, index);
156158
if (!try_get_word(memory, entry, &entry_prel_pc)) {
157159
break;
158160
}
159161
uintptr_t entry_pc = prel_to_absolute(entry, entry_prel_pc);
162+
ALOGV("XXX entry_pc=0x%08x", entry_pc);
160163
if (pc < entry_pc) {
161164
high = index;
162165
continue;
@@ -168,6 +171,7 @@ static uintptr_t get_exception_handler(const memory_t* memory,
168171
break;
169172
}
170173
uintptr_t next_entry_pc = prel_to_absolute(next_entry, next_entry_prel_pc);
174+
ALOGV("XXX next_entry_pc=0x%08x", next_entry_pc);
171175
if (pc >= next_entry_pc) {
172176
low = index + 1;
173177
continue;
@@ -184,17 +188,18 @@ static uintptr_t get_exception_handler(const memory_t* memory,
184188
} else if (entry_handler != EXIDX_CANTUNWIND) {
185189
handler = prel_to_absolute(entry_handler_ptr, entry_handler);
186190
}
191+
handler_index = index;
187192
break;
188193
}
189194
}
190195
if (mi) {
191196
ALOGV("get_exception_handler: pc=0x%08x, module='%s', module_start=0x%08x, "
192-
"exidx_start=0x%08x, exidx_size=%d, handler=0x%08x",
193-
pc, mi->name, mi->start, exidx_start, exidx_size, handler);
197+
"exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
198+
pc, mi->name, mi->start, exidx_start, exidx_size, handler, handler_index);
194199
} else {
195200
ALOGV("get_exception_handler: pc=0x%08x, "
196-
"exidx_start=0x%08x, exidx_size=%d, handler=0x%08x",
197-
pc, exidx_start, exidx_size, handler);
201+
"exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
202+
pc, exidx_start, exidx_size, handler, handler_index);
198203
}
199204
return handler;
200205
}
@@ -464,11 +469,10 @@ uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) {
464469
* 18896: 4798 blx r3
465470
* 18898: b001 add sp, #4
466471
*/
467-
pc &= ~1;
468472
uint16_t prev1, prev2;
469-
if (try_get_half_word(memory, pc - 4, &prev1)
473+
if (try_get_half_word(memory, pc - 5, &prev1)
470474
&& ((prev1 & 0xf000) == 0xf000)
471-
&& try_get_half_word(memory, pc - 2, &prev2)
475+
&& try_get_half_word(memory, pc - 3, &prev2)
472476
&& ((prev2 & 0xe000) == 0xe000)) {
473477
pc -= 4; // long offset
474478
} else {

libcorkscrew/backtrace.c

+32-6
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,9 @@ ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
213213

214214
static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) {
215215
symbol->relative_pc = pc;
216+
symbol->relative_symbol_addr = 0;
216217
symbol->map_name = NULL;
217-
symbol->name = NULL;
218+
symbol->symbol_name = NULL;
218219
symbol->demangled_name = NULL;
219220
}
220221

@@ -235,8 +236,10 @@ void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
235236
#if HAVE_DLADDR
236237
Dl_info info;
237238
if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
238-
symbol->name = strdup(info.dli_sname);
239-
symbol->demangled_name = demangle_symbol_name(symbol->name);
239+
symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr
240+
- (uintptr_t)info.dli_fbase;
241+
symbol->symbol_name = strdup(info.dli_sname);
242+
symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
240243
}
241244
#endif
242245
}
@@ -262,8 +265,9 @@ void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
262265
}
263266
}
264267
if (s) {
265-
symbol->name = strdup(s->name);
266-
symbol->demangled_name = demangle_symbol_name(symbol->name);
268+
symbol->relative_symbol_addr = s->start;
269+
symbol->symbol_name = strdup(s->name);
270+
symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
267271
}
268272
}
269273
}
@@ -272,8 +276,30 @@ void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames
272276
for (size_t i = 0; i < frames; i++) {
273277
backtrace_symbol_t* symbol = &backtrace_symbols[i];
274278
free(symbol->map_name);
275-
free(symbol->name);
279+
free(symbol->symbol_name);
276280
free(symbol->demangled_name);
277281
init_backtrace_symbol(symbol, 0);
278282
}
279283
}
284+
285+
void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame,
286+
const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) {
287+
const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>";
288+
const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name;
289+
size_t fieldWidth = (bufferSize - 80) / 2;
290+
if (symbolName) {
291+
uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
292+
if (pc_offset) {
293+
snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s+%u)",
294+
frameNumber, symbol->relative_pc, fieldWidth, mapName,
295+
fieldWidth, symbolName, pc_offset);
296+
} else {
297+
snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s)",
298+
frameNumber, symbol->relative_pc, fieldWidth, mapName,
299+
fieldWidth, symbolName);
300+
}
301+
} else {
302+
snprintf(buffer, bufferSize, "#%02d pc %08x %.*s",
303+
frameNumber, symbol->relative_pc, fieldWidth, mapName);
304+
}
305+
}

libcorkscrew/symbol_table.c

+7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static int bcompar(const void *key, const void *element) {
4747

4848
symbol_table_t* load_symbol_table(const char *filename) {
4949
symbol_table_t* table = NULL;
50+
ALOGV("Loading symbol table from '%s'.", filename);
5051

5152
int fd = open(filename, O_RDONLY);
5253
if (fd < 0) {
@@ -154,6 +155,9 @@ symbol_table_t* load_symbol_table(const char *filename) {
154155
table->symbols[symbol_index].name = strdup(dynstr + dynsyms[i].st_name);
155156
table->symbols[symbol_index].start = dynsyms[i].st_value;
156157
table->symbols[symbol_index].end = dynsyms[i].st_value + dynsyms[i].st_size;
158+
ALOGV(" [%d] '%s' 0x%08x-0x%08x (DYNAMIC)",
159+
symbol_index, table->symbols[symbol_index].name,
160+
table->symbols[symbol_index].start, table->symbols[symbol_index].end);
157161
symbol_index += 1;
158162
}
159163
}
@@ -169,6 +173,9 @@ symbol_table_t* load_symbol_table(const char *filename) {
169173
table->symbols[symbol_index].name = strdup(str + syms[i].st_name);
170174
table->symbols[symbol_index].start = syms[i].st_value;
171175
table->symbols[symbol_index].end = syms[i].st_value + syms[i].st_size;
176+
ALOGV(" [%d] '%s' 0x%08x-0x%08x",
177+
symbol_index, table->symbols[symbol_index].name,
178+
table->symbols[symbol_index].start, table->symbols[symbol_index].end);
172179
symbol_index += 1;
173180
}
174181
}

0 commit comments

Comments
 (0)