1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "Corkscrew" 18 //#define LOG_NDEBUG 0 19 20 #include <corkscrew/symbol_table.h> 21 22 #include <stdbool.h> 23 #include <stdlib.h> 24 #include <fcntl.h> 25 #include <string.h> 26 #include <sys/stat.h> 27 #include <sys/mman.h> 28 #include <cutils/log.h> 29 30 #if defined(__APPLE__) 31 #else 32 33 #include <elf.h> 34 35 static bool is_elf(Elf32_Ehdr* e) { 36 return (e->e_ident[EI_MAG0] == ELFMAG0 && 37 e->e_ident[EI_MAG1] == ELFMAG1 && 38 e->e_ident[EI_MAG2] == ELFMAG2 && 39 e->e_ident[EI_MAG3] == ELFMAG3); 40 } 41 42 #endif 43 44 // Compare function for qsort 45 static int qcompar(const void *a, const void *b) { 46 const symbol_t* asym = (const symbol_t*)a; 47 const symbol_t* bsym = (const symbol_t*)b; 48 if (asym->start > bsym->start) return 1; 49 if (asym->start < bsym->start) return -1; 50 return 0; 51 } 52 53 // Compare function for bsearch 54 static int bcompar(const void *key, const void *element) { 55 uintptr_t addr = *(const uintptr_t*)key; 56 const symbol_t* symbol = (const symbol_t*)element; 57 if (addr < symbol->start) return -1; 58 if (addr >= symbol->end) return 1; 59 return 0; 60 } 61 62 symbol_table_t* load_symbol_table(const char *filename) { 63 symbol_table_t* table = NULL; 64 #if !defined(__APPLE__) 65 ALOGV("Loading symbol table from '%s'.", filename); 66 67 int fd = open(filename, O_RDONLY); 68 if (fd < 0) { 69 goto out; 70 } 71 72 struct stat sb; 73 if (fstat(fd, &sb)) { 74 goto out_close; 75 } 76 77 size_t length = sb.st_size; 78 char* base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0); 79 if (base == MAP_FAILED) { 80 goto out_close; 81 } 82 83 // Parse the file header 84 Elf32_Ehdr *hdr = (Elf32_Ehdr*)base; 85 if (!is_elf(hdr)) { 86 goto out_close; 87 } 88 Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff); 89 90 // Search for the dynamic symbols section 91 int sym_idx = -1; 92 int dynsym_idx = -1; 93 for (Elf32_Half i = 0; i < hdr->e_shnum; i++) { 94 if (shdr[i].sh_type == SHT_SYMTAB) { 95 sym_idx = i; 96 } 97 if (shdr[i].sh_type == SHT_DYNSYM) { 98 dynsym_idx = i; 99 } 100 } 101 if (dynsym_idx == -1 && sym_idx == -1) { 102 goto out_unmap; 103 } 104 105 table = malloc(sizeof(symbol_table_t)); 106 if(!table) { 107 goto out_unmap; 108 } 109 table->num_symbols = 0; 110 111 Elf32_Sym *dynsyms = NULL; 112 int dynnumsyms = 0; 113 char *dynstr = NULL; 114 if (dynsym_idx != -1) { 115 dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset); 116 dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize; 117 int dynstr_idx = shdr[dynsym_idx].sh_link; 118 dynstr = base + shdr[dynstr_idx].sh_offset; 119 } 120 121 Elf32_Sym *syms = NULL; 122 int numsyms = 0; 123 char *str = NULL; 124 if (sym_idx != -1) { 125 syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset); 126 numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize; 127 int str_idx = shdr[sym_idx].sh_link; 128 str = base + shdr[str_idx].sh_offset; 129 } 130 131 int dynsymbol_count = 0; 132 if (dynsym_idx != -1) { 133 // Iterate through the dynamic symbol table, and count how many symbols 134 // are actually defined 135 for (int i = 0; i < dynnumsyms; i++) { 136 if (dynsyms[i].st_shndx != SHN_UNDEF) { 137 dynsymbol_count++; 138 } 139 } 140 } 141 142 size_t symbol_count = 0; 143 if (sym_idx != -1) { 144 // Iterate through the symbol table, and count how many symbols 145 // are actually defined 146 for (int i = 0; i < numsyms; i++) { 147 if (syms[i].st_shndx != SHN_UNDEF 148 && str[syms[i].st_name] 149 && syms[i].st_value 150 && syms[i].st_size) { 151 symbol_count++; 152 } 153 } 154 } 155 156 // Now, create an entry in our symbol table structure for each symbol... 157 table->num_symbols += symbol_count + dynsymbol_count; 158 table->symbols = malloc(table->num_symbols * sizeof(symbol_t)); 159 if (!table->symbols) { 160 free(table); 161 table = NULL; 162 goto out_unmap; 163 } 164 165 size_t symbol_index = 0; 166 if (dynsym_idx != -1) { 167 // ...and populate them 168 for (int i = 0; i < dynnumsyms; i++) { 169 if (dynsyms[i].st_shndx != SHN_UNDEF) { 170 table->symbols[symbol_index].name = strdup(dynstr + dynsyms[i].st_name); 171 table->symbols[symbol_index].start = dynsyms[i].st_value; 172 table->symbols[symbol_index].end = dynsyms[i].st_value + dynsyms[i].st_size; 173 ALOGV(" [%d] '%s' 0x%08x-0x%08x (DYNAMIC)", 174 symbol_index, table->symbols[symbol_index].name, 175 table->symbols[symbol_index].start, table->symbols[symbol_index].end); 176 symbol_index += 1; 177 } 178 } 179 } 180 181 if (sym_idx != -1) { 182 // ...and populate them 183 for (int i = 0; i < numsyms; i++) { 184 if (syms[i].st_shndx != SHN_UNDEF 185 && str[syms[i].st_name] 186 && syms[i].st_value 187 && syms[i].st_size) { 188 table->symbols[symbol_index].name = strdup(str + syms[i].st_name); 189 table->symbols[symbol_index].start = syms[i].st_value; 190 table->symbols[symbol_index].end = syms[i].st_value + syms[i].st_size; 191 ALOGV(" [%d] '%s' 0x%08x-0x%08x", 192 symbol_index, table->symbols[symbol_index].name, 193 table->symbols[symbol_index].start, table->symbols[symbol_index].end); 194 symbol_index += 1; 195 } 196 } 197 } 198 199 // Sort the symbol table entries, so they can be bsearched later 200 qsort(table->symbols, table->num_symbols, sizeof(symbol_t), qcompar); 201 202 out_unmap: 203 munmap(base, length); 204 205 out_close: 206 close(fd); 207 #endif 208 209 out: 210 return table; 211 } 212 213 void free_symbol_table(symbol_table_t* table) { 214 if (table) { 215 for (size_t i = 0; i < table->num_symbols; i++) { 216 free(table->symbols[i].name); 217 } 218 free(table->symbols); 219 free(table); 220 } 221 } 222 223 const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr) { 224 if (!table) return NULL; 225 return (const symbol_t*)bsearch(&addr, table->symbols, table->num_symbols, 226 sizeof(symbol_t), bcompar); 227 } 228