Merge "debuggerd: Show function names in tombstone backtraces"
This commit is contained in:
commit
13b012aaff
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue