1 /* libunwind - a platform-independent unwind library 2 Copyright (C) 2003-2005 Hewlett-Packard Co 3 Copyright (C) 2007 David Mosberger-Tang 4 Contributed by David Mosberger-Tang <dmosberger (at) gmail.com> 5 6 This file is part of libunwind. 7 8 Permission is hereby granted, free of charge, to any person obtaining 9 a copy of this software and associated documentation files (the 10 "Software"), to deal in the Software without restriction, including 11 without limitation the rights to use, copy, modify, merge, publish, 12 distribute, sublicense, and/or sell copies of the Software, and to 13 permit persons to whom the Software is furnished to do so, subject to 14 the following conditions: 15 16 The above copyright notice and this permission notice shall be 17 included in all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 26 27 #include "libunwind_i.h" 28 29 #include <stdio.h> 30 #include <sys/param.h> 31 32 #ifdef HAVE_LZMA 33 #include <lzma.h> 34 #endif /* HAVE_LZMA */ 35 36 static Elf_W (Shdr)* 37 elf_w (section_table) (struct elf_image *ei) 38 { 39 Elf_W (Ehdr) *ehdr = ei->image; 40 Elf_W (Off) soff; 41 42 soff = ehdr->e_shoff; 43 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size) 44 { 45 Debug (1, "section table outside of image? (%lu > %lu)\n", 46 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize), 47 (unsigned long) ei->size); 48 return NULL; 49 } 50 51 return (Elf_W (Shdr) *) ((char *) ei->image + soff); 52 } 53 54 static char* 55 elf_w (string_table) (struct elf_image *ei, int section) 56 { 57 Elf_W (Ehdr) *ehdr = ei->image; 58 Elf_W (Off) soff, str_soff; 59 Elf_W (Shdr) *str_shdr; 60 61 /* this offset is assumed to be OK */ 62 soff = ehdr->e_shoff; 63 64 str_soff = soff + (section * ehdr->e_shentsize); 65 if (str_soff + ehdr->e_shentsize > ei->size) 66 { 67 Debug (1, "string shdr table outside of image? (%lu > %lu)\n", 68 (unsigned long) (str_soff + ehdr->e_shentsize), 69 (unsigned long) ei->size); 70 return NULL; 71 } 72 str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff); 73 74 if (str_shdr->sh_offset + str_shdr->sh_size > ei->size) 75 { 76 Debug (1, "string table outside of image? (%lu > %lu)\n", 77 (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size), 78 (unsigned long) ei->size); 79 return NULL; 80 } 81 82 Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset); 83 /* End of ANDROID update. */ 84 return (char*) ((uintptr_t) ei->image + str_shdr->sh_offset); 85 /* End of ANDROID update. */ 86 } 87 88 static int 89 elf_w (lookup_symbol) (unw_addr_space_t as, 90 unw_word_t ip, struct elf_image *ei, 91 Elf_W (Addr) load_offset, 92 char *buf, size_t buf_len, Elf_W (Addr) *min_dist) 93 { 94 size_t syment_size; 95 Elf_W (Ehdr) *ehdr = ei->image; 96 Elf_W (Sym) *sym, *symtab, *symtab_end; 97 Elf_W (Shdr) *shdr; 98 Elf_W (Addr) val; 99 int i, ret = -UNW_ENOINFO; 100 char *strtab; 101 102 if (!elf_w (valid_object) (ei)) 103 return -UNW_ENOINFO; 104 105 shdr = elf_w (section_table) (ei); 106 if (!shdr) 107 return -UNW_ENOINFO; 108 109 for (i = 0; i < ehdr->e_shnum; ++i) 110 { 111 switch (shdr->sh_type) 112 { 113 case SHT_SYMTAB: 114 case SHT_DYNSYM: 115 symtab = (Elf_W (Sym) *) ((char *) ei->image + shdr->sh_offset); 116 symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size); 117 syment_size = shdr->sh_entsize; 118 119 strtab = elf_w (string_table) (ei, shdr->sh_link); 120 if (!strtab) 121 break; 122 123 Debug (16, "symtab=0x%lx[%d]\n", 124 (long) shdr->sh_offset, shdr->sh_type); 125 126 for (sym = symtab; 127 sym < symtab_end; 128 sym = (Elf_W (Sym) *) ((char *) sym + syment_size)) 129 { 130 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC 131 && sym->st_shndx != SHN_UNDEF) 132 { 133 if (tdep_get_func_addr (as, sym->st_value, &val) < 0) 134 continue; 135 if (sym->st_shndx != SHN_ABS) 136 val += load_offset; 137 Debug (16, "0x%016lx info=0x%02x %s\n", 138 (long) val, sym->st_info, strtab + sym->st_name); 139 140 /* ANDROID support update */ 141 if ((Elf_W (Addr)) (ip - val) < *min_dist 142 && (Elf_W (Addr)) (ip - val) < sym->st_size) 143 /* End of ANDROID update */ 144 { 145 *min_dist = (Elf_W (Addr)) (ip - val); 146 strncpy (buf, strtab + sym->st_name, buf_len); 147 buf[buf_len - 1] = '\0'; 148 ret = (strlen (strtab + sym->st_name) >= buf_len 149 ? -UNW_ENOMEM : 0); 150 } 151 } 152 } 153 break; 154 155 default: 156 break; 157 } 158 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); 159 } 160 return ret; 161 } 162 163 static Elf_W (Addr) 164 elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase, 165 unsigned long mapoff) 166 { 167 Elf_W (Addr) offset = 0; 168 Elf_W (Ehdr) *ehdr; 169 Elf_W (Phdr) *phdr; 170 int i; 171 172 ehdr = ei->image; 173 phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff); 174 175 for (i = 0; i < ehdr->e_phnum; ++i) 176 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) 177 { 178 offset = segbase - phdr[i].p_vaddr; 179 break; 180 } 181 182 return offset; 183 } 184 185 #if HAVE_LZMA 186 static size_t 187 xz_uncompressed_size (uint8_t *compressed, size_t length) 188 { 189 uint64_t memlimit = UINT64_MAX; 190 size_t ret = 0, pos = 0; 191 lzma_stream_flags options; 192 lzma_index *index; 193 194 if (length < LZMA_STREAM_HEADER_SIZE) 195 return 0; 196 197 uint8_t *footer = compressed + length - LZMA_STREAM_HEADER_SIZE; 198 if (lzma_stream_footer_decode (&options, footer) != LZMA_OK) 199 return 0; 200 201 if (length < LZMA_STREAM_HEADER_SIZE + options.backward_size) 202 return 0; 203 204 uint8_t *indexdata = footer - options.backward_size; 205 if (lzma_index_buffer_decode (&index, &memlimit, NULL, indexdata, 206 &pos, options.backward_size) != LZMA_OK) 207 return 0; 208 209 if (lzma_index_size (index) == options.backward_size) 210 { 211 ret = lzma_index_uncompressed_size (index); 212 } 213 214 lzma_index_end (index, NULL); 215 return ret; 216 } 217 218 static int 219 elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi) 220 { 221 Elf_W (Ehdr) *ehdr = ei->image; 222 Elf_W (Shdr) *shdr; 223 char *strtab; 224 int i; 225 uint8_t *compressed = NULL; 226 uint64_t memlimit = UINT64_MAX; /* no memory limit */ 227 size_t compressed_len, uncompressed_len; 228 229 if (!elf_w (valid_object) (ei)) 230 return 0; 231 232 shdr = elf_w (section_table) (ei); 233 if (!shdr) 234 return 0; 235 236 strtab = elf_w (string_table) (ei, ehdr->e_shstrndx); 237 if (!strtab) 238 return 0; 239 240 for (i = 0; i < ehdr->e_shnum; ++i) 241 { 242 if (strcmp (strtab + shdr->sh_name, ".gnu_debugdata") == 0) 243 { 244 if (shdr->sh_offset + shdr->sh_size > ei->size) 245 { 246 Debug (1, ".gnu_debugdata outside image? (0x%lu > 0x%lu)\n", 247 (unsigned long) shdr->sh_offset + shdr->sh_size, 248 (unsigned long) ei->size); 249 return 0; 250 } 251 252 Debug (16, "found .gnu_debugdata at 0x%lx\n", 253 (unsigned long) shdr->sh_offset); 254 compressed = ((uint8_t *) ei->image) + shdr->sh_offset; 255 compressed_len = shdr->sh_size; 256 break; 257 } 258 259 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); 260 } 261 262 /* not found */ 263 if (!compressed) 264 return 0; 265 266 uncompressed_len = xz_uncompressed_size (compressed, compressed_len); 267 if (uncompressed_len == 0) 268 { 269 Debug (1, "invalid .gnu_debugdata contents\n"); 270 return 0; 271 } 272 273 mdi->size = uncompressed_len; 274 mdi->image = mmap (NULL, uncompressed_len, PROT_READ|PROT_WRITE, 275 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 276 277 if (mdi->image == MAP_FAILED) 278 return 0; 279 280 size_t in_pos = 0, out_pos = 0; 281 lzma_ret lret; 282 lret = lzma_stream_buffer_decode (&memlimit, 0, NULL, 283 compressed, &in_pos, compressed_len, 284 mdi->image, &out_pos, mdi->size); 285 if (lret != LZMA_OK) 286 { 287 Debug (1, "LZMA decompression failed: %d\n", lret); 288 munmap (mdi->image, mdi->size); 289 return 0; 290 } 291 292 return 1; 293 } 294 #else 295 static int 296 elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi) 297 { 298 return 0; 299 } 300 #endif /* !HAVE_LZMA */ 301 302 /* Find the ELF image that contains IP and return the "closest" 303 procedure name, if there is one. With some caching, this could be 304 sped up greatly, but until an application materializes that's 305 sensitive to the performance of this routine, why bother... */ 306 307 HIDDEN int 308 elf_w (get_proc_name_in_image) (unw_addr_space_t as, struct elf_image *ei, 309 unsigned long segbase, 310 unsigned long mapoff, 311 unw_word_t ip, 312 char *buf, size_t buf_len, unw_word_t *offp) 313 { 314 Elf_W (Addr) load_offset; 315 Elf_W (Addr) min_dist = ~(Elf_W (Addr))0; 316 int ret; 317 318 load_offset = elf_w (get_load_offset) (ei, segbase, mapoff); 319 ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, &min_dist); 320 321 /* If the ELF image has MiniDebugInfo embedded in it, look up the symbol in 322 there as well and replace the previously found if it is closer. */ 323 struct elf_image mdi; 324 if (elf_w (extract_minidebuginfo) (ei, &mdi)) 325 { 326 int ret_mdi; 327 328 load_offset = elf_w (get_load_offset) (&mdi, segbase, mapoff); 329 ret_mdi = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, 330 buf_len, &min_dist); 331 332 /* Closer symbol was found (possibly truncated). */ 333 if (ret_mdi == 0 || ret_mdi == -UNW_ENOMEM) 334 { 335 ret = ret_mdi; 336 } 337 338 munmap (mdi.image, mdi.size); 339 } 340 341 if (min_dist >= ei->size) 342 return -UNW_ENOINFO; /* not found */ 343 if (offp) 344 *offp = min_dist; 345 return ret; 346 } 347 348 /* ANDROID support update. */ 349 HIDDEN int 350 elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip, 351 char *buf, size_t buf_len, unw_word_t *offp) 352 { 353 unsigned long segbase, mapoff; 354 struct elf_image ei; 355 int ret; 356 357 ret = tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL); 358 if (ret < 0) 359 return ret; 360 361 return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp); 362 } 363 /* ANDROID support update. */ 364