Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07ff3b87 authored by Steve Kondik's avatar Steve Kondik Committed by Gerrit Code Review
Browse files

Merge "debuggerd: Show function names in tombstone backtraces" into gingerbread

parents 033f8681 b09991e5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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

+9 −4
Original line number Diff line number Diff line
@@ -63,7 +63,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);
@@ -106,10 +106,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);

@@ -399,7 +400,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) {
@@ -429,6 +430,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);
        }
    }
}
@@ -466,7 +470,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.
@@ -485,6 +489,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 −0
Original line number Diff line number Diff line
#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 −0
Original line number Diff line number Diff line
#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
+17 −3
Original line number Diff line number Diff line
@@ -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);

    /* 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;
}
Loading