Home | History | Annotate | Download | only in debuggerd
      1 #include <stdlib.h>
      2 #include <fcntl.h>
      3 #include <string.h>
      4 #include <sys/stat.h>
      5 #include <sys/mman.h>
      6 
      7 #include "symbol_table.h"
      8 #include "utility.h"
      9 
     10 #include <linux/elf.h>
     11 
     12 // Compare func for qsort
     13 static int qcompar(const void *a, const void *b)
     14 {
     15     return ((struct symbol*)a)->addr - ((struct symbol*)b)->addr;
     16 }
     17 
     18 // Compare func for bsearch
     19 static int bcompar(const void *addr, const void *element)
     20 {
     21     struct symbol *symbol = (struct symbol*)element;
     22 
     23     if((unsigned int)addr < symbol->addr) {
     24         return -1;
     25     }
     26 
     27     if((unsigned int)addr - symbol->addr >= symbol->size) {
     28         return 1;
     29     }
     30 
     31     return 0;
     32 }
     33 
     34 /*
     35  *  Create a symbol table from a given file
     36  *
     37  *  Parameters:
     38  *      filename - Filename to process
     39  *
     40  *  Returns:
     41  *      A newly-allocated SymbolTable structure, or NULL if error.
     42  *      Free symbol table with symbol_table_free()
     43  */
     44 struct symbol_table *symbol_table_create(const char *filename)
     45 {
     46     struct symbol_table *table = NULL;
     47 
     48     // Open the file, and map it into memory
     49     struct stat sb;
     50     int length;
     51     char *base;
     52 
     53     XLOG2("Creating symbol table for %s\n", filename);
     54     int fd = open(filename, O_RDONLY);
     55 
     56     if(fd < 0) {
     57         goto out;
     58     }
     59 
     60     fstat(fd, &sb);
     61     length = sb.st_size;
     62 
     63     base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
     64 
     65     if(!base) {
     66         goto out_close;
     67     }
     68 
     69     // Parse the file header
     70     Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
     71     Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
     72 
     73     // Search for the dynamic symbols section
     74     int sym_idx = -1;
     75     int dynsym_idx = -1;
     76     int i;
     77 
     78     for(i = 0; i < hdr->e_shnum; i++) {
     79         if(shdr[i].sh_type == SHT_SYMTAB ) {
     80             sym_idx = i;
     81         }
     82         if(shdr[i].sh_type == SHT_DYNSYM ) {
     83             dynsym_idx = i;
     84         }
     85     }
     86     if ((dynsym_idx == -1) && (sym_idx == -1)) {
     87         goto out_unmap;
     88     }
     89 
     90     table = malloc(sizeof(struct symbol_table));
     91     if(!table) {
     92         goto out_unmap;
     93     }
     94     table->name = strdup(filename);
     95     table->num_symbols = 0;
     96 
     97     Elf32_Sym *dynsyms = NULL;
     98     Elf32_Sym *syms = NULL;
     99     int dynnumsyms = 0;
    100     int numsyms = 0;
    101     char *dynstr = NULL;
    102     char *str = NULL;
    103 
    104     if (dynsym_idx != -1) {
    105         dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
    106         dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
    107         int dynstr_idx = shdr[dynsym_idx].sh_link;
    108         dynstr = base + shdr[dynstr_idx].sh_offset;
    109     }
    110 
    111     if (sym_idx != -1) {
    112         syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset);
    113         numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize;
    114         int str_idx = shdr[sym_idx].sh_link;
    115         str = base + shdr[str_idx].sh_offset;
    116     }
    117 
    118     int symbol_count = 0;
    119     int dynsymbol_count = 0;
    120 
    121     if (dynsym_idx != -1) {
    122         // Iterate through the dynamic symbol table, and count how many symbols
    123         // are actually defined
    124         for(i = 0; i < dynnumsyms; i++) {
    125             if(dynsyms[i].st_shndx != SHN_UNDEF) {
    126                 dynsymbol_count++;
    127             }
    128         }
    129         XLOG2("Dynamic Symbol count: %d\n", dynsymbol_count);
    130     }
    131 
    132     if (sym_idx != -1) {
    133         // Iterate through the symbol table, and count how many symbols
    134         // are actually defined
    135         for(i = 0; i < numsyms; i++) {
    136             if((syms[i].st_shndx != SHN_UNDEF) &&
    137                 (strlen(str+syms[i].st_name)) &&
    138                 (syms[i].st_value != 0) && (syms[i].st_size != 0)) {
    139                 symbol_count++;
    140             }
    141         }
    142         XLOG2("Symbol count: %d\n", symbol_count);
    143     }
    144 
    145     // Now, create an entry in our symbol table structure for each symbol...
    146     table->num_symbols += symbol_count + dynsymbol_count;
    147     table->symbols = malloc(table->num_symbols * sizeof(struct symbol));
    148     if(!table->symbols) {
    149         free(table);
    150         table = NULL;
    151         goto out_unmap;
    152     }
    153 
    154 
    155     int j = 0;
    156     if (dynsym_idx != -1) {
    157         // ...and populate them
    158         for(i = 0; i < dynnumsyms; i++) {
    159             if(dynsyms[i].st_shndx != SHN_UNDEF) {
    160                 table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
    161                 table->symbols[j].addr = dynsyms[i].st_value;
    162                 table->symbols[j].size = dynsyms[i].st_size;
    163                 XLOG2("name: %s, addr: %x, size: %x\n",
    164                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
    165                 j++;
    166             }
    167         }
    168     }
    169 
    170     if (sym_idx != -1) {
    171         // ...and populate them
    172         for(i = 0; i < numsyms; i++) {
    173             if((syms[i].st_shndx != SHN_UNDEF) &&
    174                 (strlen(str+syms[i].st_name)) &&
    175                 (syms[i].st_value != 0) && (syms[i].st_size != 0)) {
    176                 table->symbols[j].name = strdup(str + syms[i].st_name);
    177                 table->symbols[j].addr = syms[i].st_value;
    178                 table->symbols[j].size = syms[i].st_size;
    179                 XLOG2("name: %s, addr: %x, size: %x\n",
    180                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
    181                 j++;
    182             }
    183         }
    184     }
    185 
    186     // Sort the symbol table entries, so they can be bsearched later
    187     qsort(table->symbols, table->num_symbols, sizeof(struct symbol), qcompar);
    188 
    189 out_unmap:
    190     munmap(base, length);
    191 
    192 out_close:
    193     close(fd);
    194 
    195 out:
    196     return table;
    197 }
    198 
    199 /*
    200  * Free a symbol table
    201  *
    202  * Parameters:
    203  *     table - Table to free
    204  */
    205 void symbol_table_free(struct symbol_table *table)
    206 {
    207     int i;
    208 
    209     if(!table) {
    210         return;
    211     }
    212 
    213     for(i=0; i<table->num_symbols; i++) {
    214         free(table->symbols[i].name);
    215     }
    216 
    217     free(table->symbols);
    218     free(table);
    219 }
    220 
    221 /*
    222  * Search for an address in the symbol table
    223  *
    224  * Parameters:
    225  *      table - Table to search in
    226  *      addr - Address to search for.
    227  *
    228  * Returns:
    229  *      A pointer to the Symbol structure corresponding to the
    230  *      symbol which contains this address, or NULL if no symbol
    231  *      contains it.
    232  */
    233 const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr)
    234 {
    235     if(!table) {
    236         return NULL;
    237     }
    238 
    239     return bsearch((void*)addr, table->symbols, table->num_symbols, sizeof(struct symbol), bcompar);
    240 }
    241