Merge "debuggerd: Show function names in tombstone backtraces"

This commit is contained in:
Jean-Baptiste Queru 2010-06-09 17:21:03 -07:00 committed by Android Code Review
commit 13b012aaff
6 changed files with 227 additions and 8 deletions

View File

@ -5,7 +5,7 @@ ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c
LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c symbol_table.c
LOCAL_CFLAGS := -Wall
LOCAL_MODULE := debuggerd

View File

@ -55,7 +55,7 @@ static int logsocket = -1;
/* Log information onto the tombstone */
void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...)
{
char buf[128];
char buf[512];
va_list ap;
va_start(ap, fmt);
@ -98,10 +98,11 @@ mapinfo *parse_maps_line(char *line)
mi->start = strtoul(line, 0, 16);
mi->end = strtoul(line + 9, 0, 16);
/* To be filled in parse_exidx_info if the mapped section starts with
/* To be filled in parse_elf_info if the mapped section starts with
* elf_header
*/
mi->exidx_start = mi->exidx_end = 0;
mi->symbols = 0;
mi->next = 0;
strcpy(mi->name, line + 49);
@ -335,7 +336,7 @@ void dump_crash_banner(int tfd, unsigned pid, unsigned tid, int sig)
if(sig) dump_fault_addr(tfd, tid, sig);
}
static void parse_exidx_info(mapinfo *milist, pid_t pid)
static void parse_elf_info(mapinfo *milist, pid_t pid)
{
mapinfo *mi;
for (mi = milist; mi != NULL; mi = mi->next) {
@ -365,6 +366,9 @@ static void parse_exidx_info(mapinfo *milist, pid_t pid)
break;
}
}
/* Try to load symbols from this file */
mi->symbols = symbol_table_create(mi->name);
}
}
}
@ -402,7 +406,7 @@ void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault)
fclose(fp);
}
parse_exidx_info(milist, tid);
parse_elf_info(milist, tid);
/* If stack unwinder fails, use the default solution to dump the stack
* content.
@ -422,6 +426,7 @@ void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault)
while(milist) {
mapinfo *next = milist->next;
symbol_table_free(milist->symbols);
free(milist);
milist = next;
}

178
debuggerd/symbol_table.c Normal file
View File

@ -0,0 +1,178 @@
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "symbol_table.h"
#include <linux/elf.h>
// Compare func for qsort
static int qcompar(const void *a, const void *b)
{
return ((struct symbol*)a)->addr - ((struct symbol*)b)->addr;
}
// Compare func for bsearch
static int bcompar(const void *addr, const void *element)
{
struct symbol *symbol = (struct symbol*)element;
if((unsigned int)addr < symbol->addr) {
return -1;
}
if((unsigned int)addr - symbol->addr >= symbol->size) {
return 1;
}
return 0;
}
/*
* Create a symbol table from a given file
*
* Parameters:
* filename - Filename to process
*
* Returns:
* A newly-allocated SymbolTable structure, or NULL if error.
* Free symbol table with symbol_table_free()
*/
struct symbol_table *symbol_table_create(const char *filename)
{
struct symbol_table *table = NULL;
// Open the file, and map it into memory
struct stat sb;
int length;
char *base;
int fd = open(filename, O_RDONLY);
if(fd < 0) {
goto out;
}
fstat(fd, &sb);
length = sb.st_size;
base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if(!base) {
goto out_close;
}
// Parse the file header
Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
// Search for the dynamic symbols section
int dynsym_idx = -1;
int i;
for(i = 0; i < hdr->e_shnum; i++) {
if(shdr[i].sh_type == SHT_DYNSYM ) {
dynsym_idx = i;
}
}
if(dynsym_idx == -1) {
goto out_unmap;
}
Elf32_Sym *dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
int numsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
table = malloc(sizeof(struct symbol_table));
if(!table) {
goto out_unmap;
}
table->num_symbols = 0;
// Iterate through the dynamic symbol table, and count how many symbols
// are actually defined
for(i = 0; i < numsyms; i++) {
if(dynsyms[i].st_shndx != SHN_UNDEF) {
table->num_symbols++;
}
}
int dynstr_idx = shdr[dynsym_idx].sh_link;
char *dynstr = base + shdr[dynstr_idx].sh_offset;
// Now, create an entry in our symbol table structure for each symbol...
table->symbols = malloc(table->num_symbols * sizeof(struct symbol));
if(!table->symbols) {
free(table);
table = NULL;
goto out_unmap;
}
// ...and populate them
int j = 0;
for(i = 0; i < numsyms; i++) {
if(dynsyms[i].st_shndx != SHN_UNDEF) {
table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
table->symbols[j].addr = dynsyms[i].st_value;
table->symbols[j].size = dynsyms[i].st_size;
j++;
}
}
// Sort the symbol table entries, so they can be bsearched later
qsort(table->symbols, table->num_symbols, sizeof(struct symbol), qcompar);
out_unmap:
munmap(base, length);
out_close:
close(fd);
out:
return table;
}
/*
* Free a symbol table
*
* Parameters:
* table - Table to free
*/
void symbol_table_free(struct symbol_table *table)
{
int i;
if(!table) {
return;
}
for(i=0; i<table->num_symbols; i++) {
free(table->symbols[i].name);
}
free(table->symbols);
free(table);
}
/*
* Search for an address in the symbol table
*
* Parameters:
* table - Table to search in
* addr - Address to search for.
*
* Returns:
* A pointer to the Symbol structure corresponding to the
* symbol which contains this address, or NULL if no symbol
* contains it.
*/
const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr)
{
if(!table) {
return NULL;
}
return bsearch((void*)addr, table->symbols, table->num_symbols, sizeof(struct symbol), bcompar);
}

19
debuggerd/symbol_table.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef SYMBOL_TABLE_H
#define SYMBOL_TABLE_H
struct symbol {
unsigned int addr;
unsigned int size;
char *name;
};
struct symbol_table {
struct symbol *symbols;
int num_symbols;
};
struct symbol_table *symbol_table_create(const char *filename);
void symbol_table_free(struct symbol_table *table);
const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr);
#endif

View File

@ -37,6 +37,8 @@
#include <unwind.h>
#include "utility.h"
#include "symbol_table.h"
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
@ -393,6 +395,7 @@ static _Unwind_Reason_Code log_function(_Unwind_Context *context, pid_t pid,
phase2_vrs *vrs = (phase2_vrs*) context;
const mapinfo *mi;
bool only_in_tombstone = !at_fault;
const struct symbol* sym = 0;
if (stack_level < STACK_CONTENT_DEPTH) {
sp_list[stack_level] = vrs->core.r[R_SP];
@ -451,9 +454,20 @@ static _Unwind_Reason_Code log_function(_Unwind_Context *context, pid_t pid,
rel_pc = pc;
mi = pc_to_mapinfo(map, pc, &rel_pc);
_LOG(tfd, only_in_tombstone,
" #%02d pc %08x %s\n", stack_level, rel_pc,
mi ? mi->name : "");
/* See if we can determine what symbol this stack frame resides in */
if (mi != 0 && mi->symbols != 0) {
sym = symbol_table_lookup(mi->symbols, rel_pc);
}
if (sym) {
_LOG(tfd, only_in_tombstone,
" #%02d pc %08x %s (%s)\n", stack_level, rel_pc,
mi ? mi->name : "", sym->name);
} else {
_LOG(tfd, only_in_tombstone,
" #%02d pc %08x %s\n", stack_level, rel_pc,
mi ? mi->name : "");
}
return _URC_NO_REASON;
}

View File

@ -21,6 +21,8 @@
#include <stddef.h>
#include <stdbool.h>
#include "symbol_table.h"
#ifndef PT_ARM_EXIDX
#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */
#endif
@ -33,6 +35,7 @@ typedef struct mapinfo {
unsigned end;
unsigned exidx_start;
unsigned exidx_end;
struct symbol_table *symbols;
char name[];
} mapinfo;