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@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 #if HAVE_LZMA
33 #include <7zCrc.h>
34 #include <Xz.h>
35 #include <XzCrc64.h>
36 #endif /* HAVE_LZMA */
37
38 // --------------------------------------------------------------------------
39 // Functions to read elf data from memory.
40 // --------------------------------------------------------------------------
elf_w(memory_read)41 extern size_t elf_w (memory_read) (
42 struct elf_image* ei, unw_word_t addr, uint8_t* buffer, size_t bytes, bool string_read) {
43 uintptr_t end = ei->u.memory.end;
44 unw_accessors_t* a = unw_get_accessors (ei->u.memory.as);
45 if (end - addr < bytes) {
46 bytes = end - addr;
47 }
48 size_t bytes_read = 0;
49 unw_word_t data_word;
50 size_t align_bytes = addr & (sizeof(unw_word_t) - 1);
51 if (align_bytes != 0) {
52 if ((*a->access_mem) (ei->u.memory.as, addr & ~(sizeof(unw_word_t) - 1), &data_word,
53 0, ei->u.memory.as_arg) != 0) {
54 return 0;
55 }
56 size_t copy_bytes = MIN(sizeof(unw_word_t) - align_bytes, bytes);
57 memcpy (buffer, (uint8_t*) (&data_word) + align_bytes, copy_bytes);
58 if (string_read) {
59 // Check for nul terminator.
60 uint8_t* nul_terminator = memchr (buffer, '\0', copy_bytes);
61 if (nul_terminator != NULL) {
62 return nul_terminator - buffer;
63 }
64 }
65
66 addr += copy_bytes;
67 bytes_read += copy_bytes;
68 bytes -= copy_bytes;
69 buffer += copy_bytes;
70 }
71
72 size_t num_words = bytes / sizeof(unw_word_t);
73 size_t i;
74 for (i = 0; i < num_words; i++) {
75 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) {
76 return bytes_read;
77 }
78
79 memcpy (buffer, &data_word, sizeof(unw_word_t));
80 if (string_read) {
81 // Check for nul terminator.
82 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t));
83 if (nul_terminator != NULL) {
84 return nul_terminator - buffer + bytes_read;
85 }
86 }
87
88 addr += sizeof(unw_word_t);
89 bytes_read += sizeof(unw_word_t);
90 buffer += sizeof(unw_word_t);
91 }
92
93 size_t left_over = bytes & (sizeof(unw_word_t) - 1);
94 if (left_over) {
95 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) {
96 return bytes_read;
97 }
98
99 memcpy (buffer, &data_word, left_over);
100 if (string_read) {
101 // Check for nul terminator.
102 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t));
103 if (nul_terminator != NULL) {
104 return nul_terminator - buffer + bytes_read;
105 }
106 }
107
108 bytes_read += left_over;
109 }
110 return bytes_read;
111 }
112
elf_w(section_table_offset)113 static bool elf_w (section_table_offset) (struct elf_image* ei, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) {
114 GET_EHDR_FIELD(ei, ehdr, e_shoff, true);
115 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true);
116 GET_EHDR_FIELD(ei, ehdr, e_shnum, true);
117
118 uintptr_t size = ei->u.memory.end - ei->u.memory.start;
119 if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) {
120 Debug (1, "section table outside of image? (%lu > %lu)\n",
121 (unsigned long) (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize),
122 (unsigned long) size);
123 return false;
124 }
125
126 *offset = ehdr->e_shoff;
127 return true;
128 }
129
elf_w(string_table_offset)130 static bool elf_w (string_table_offset) (
131 struct elf_image* ei, int section, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) {
132 GET_EHDR_FIELD(ei, ehdr, e_shoff, true);
133 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true);
134 unw_word_t str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize);
135 uintptr_t size = ei->u.memory.end - ei->u.memory.start;
136 if (str_soff + ehdr->e_shentsize > size) {
137 Debug (1, "string shdr table outside of image? (%lu > %lu)\n",
138 (unsigned long) (str_soff + ehdr->e_shentsize),
139 (unsigned long) size);
140 return false;
141 }
142
143 Elf_W(Shdr) shdr;
144 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_offset);
145 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_size);
146 if (shdr.sh_offset + shdr.sh_size > size) {
147 Debug (1, "string table outside of image? (%lu > %lu)\n",
148 (unsigned long) (shdr.sh_offset + shdr.sh_size),
149 (unsigned long) size);
150 return false;
151 }
152
153 Debug (16, "strtab=0x%lx\n", (long) shdr.sh_offset);
154 *offset = shdr.sh_offset;
155 return true;
156 }
157
elf_w(lookup_symbol_memory)158 static bool elf_w (lookup_symbol_memory) (
159 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset,
160 char* buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) {
161 Elf_W(Off) shdr_offset;
162 if (!elf_w (section_table_offset) (ei, ehdr, &shdr_offset)) {
163 return false;
164 }
165
166 GET_EHDR_FIELD(ei, ehdr, e_shnum, true);
167 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true);
168 int i;
169 for (i = 0; i < ehdr->e_shnum; ++i) {
170 Elf_W(Shdr) shdr;
171 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_type);
172 switch (shdr.sh_type) {
173 case SHT_SYMTAB:
174 case SHT_DYNSYM:
175 {
176 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_link);
177
178 Elf_W(Off) strtab_offset;
179 if (!elf_w (string_table_offset) (ei, shdr.sh_link, ehdr, &strtab_offset)) {
180 continue;
181 }
182
183 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_offset);
184 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_size);
185 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_entsize);
186
187 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr.sh_offset, shdr.sh_type);
188
189 unw_word_t sym_offset;
190 unw_word_t symtab_end = shdr.sh_offset + shdr.sh_size;
191 for (sym_offset = shdr.sh_offset;
192 sym_offset < symtab_end;
193 sym_offset += shdr.sh_entsize) {
194 Elf_W(Sym) sym;
195 GET_SYM_FIELD(ei, sym_offset, &sym, st_info);
196 GET_SYM_FIELD(ei, sym_offset, &sym, st_shndx);
197
198 if (ELF_W (ST_TYPE) (sym.st_info) == STT_FUNC && sym.st_shndx != SHN_UNDEF) {
199 GET_SYM_FIELD(ei, sym_offset, &sym, st_value);
200 Elf_W(Addr) val;
201 if (tdep_get_func_addr (as, sym.st_value, &val) < 0) {
202 continue;
203 }
204 if (sym.st_shndx != SHN_ABS) {
205 val += load_offset;
206 }
207 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym.st_info);
208
209 GET_SYM_FIELD(ei, sym_offset, &sym, st_size);
210 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym.st_size) {
211 GET_SYM_FIELD(ei, sym_offset, &sym, st_name);
212 uintptr_t size = ei->u.memory.end - ei->u.memory.start;
213 Elf_W(Off) strname_offset = strtab_offset + sym.st_name;
214 if (strname_offset > size || strname_offset < strtab_offset) {
215 // Malformed elf symbol table.
216 break;
217 }
218
219 size_t bytes_read = elf_w (memory_read) (
220 ei, ei->u.memory.start + strname_offset,
221 (uint8_t*) buf, buf_len, true);
222 if (bytes_read == 0) {
223 // Empty name, so keep checking the other symbol tables
224 // for a possible match.
225 break;
226 }
227 // Ensure the string is nul terminated, it is assumed that
228 // sizeof(buf) >= buf_len + 1.
229 buf[buf_len] = '\0';
230
231 if (offp != NULL) {
232 *offp = ip - val;
233 }
234 return true;
235 }
236 }
237 }
238 break;
239 }
240
241 default:
242 break;
243 }
244 shdr_offset += ehdr->e_shentsize;
245 }
246 return false;
247 }
248
elf_w(get_load_offset_memory)249 static bool elf_w (get_load_offset_memory) (
250 struct elf_image* ei, unsigned long segbase, unsigned long mapoff,
251 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) {
252 GET_EHDR_FIELD(ei, ehdr, e_phoff, true);
253 GET_EHDR_FIELD(ei, ehdr, e_phnum, true);
254
255 unw_word_t offset = ehdr->e_phoff;
256 int i;
257 for (i = 0; i < ehdr->e_phnum; ++i) {
258 Elf_W(Phdr) phdr;
259 GET_PHDR_FIELD(ei, offset, &phdr, p_type);
260 if (phdr.p_type == PT_LOAD) {
261 GET_PHDR_FIELD(ei, offset, &phdr, p_offset);
262 if (phdr.p_offset == mapoff) {
263 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr);
264 *load_offset = segbase - phdr.p_vaddr;
265 return true;
266 }
267 }
268 offset += sizeof(Elf_W(Phdr));
269 }
270 return false;
271 }
272
273 // --------------------------------------------------------------------------
274 // Functions to read elf data from the mapped elf image.
275 // --------------------------------------------------------------------------
Elf_W(Shdr)276 static Elf_W(Shdr)* elf_w (section_table) (struct elf_image* ei) {
277 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
278 Elf_W(Off) soff = ehdr->e_shoff;
279 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->u.mapped.size) {
280 Debug (1, "section table outside of image? (%lu > %lu)\n",
281 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize),
282 (unsigned long) ei->u.mapped.size);
283 return NULL;
284 }
285
286 return (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + soff);
287 }
288
elf_w(string_table)289 static char* elf_w (string_table) (struct elf_image* ei, int section) {
290 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
291 Elf_W(Off) str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize);
292 if (str_soff + ehdr->e_shentsize > ei->u.mapped.size) {
293 Debug (1, "string shdr table outside of image? (%lu > %lu)\n",
294 (unsigned long) (str_soff + ehdr->e_shentsize),
295 (unsigned long) ei->u.mapped.size);
296 return NULL;
297 }
298 Elf_W(Shdr)* str_shdr = (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + str_soff);
299
300 if (str_shdr->sh_offset + str_shdr->sh_size > ei->u.mapped.size) {
301 Debug (1, "string table outside of image? (%lu > %lu)\n",
302 (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size),
303 (unsigned long) ei->u.mapped.size);
304 return NULL;
305 }
306
307 Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset);
308 return (char*) ((uintptr_t) ei->u.mapped.image + str_shdr->sh_offset);
309 }
310
elf_w(lookup_symbol_mapped)311 static bool elf_w (lookup_symbol_mapped) (
312 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset,
313 char* buf, size_t buf_len, unw_word_t* offp) {
314
315 Elf_W(Shdr)* shdr = elf_w (section_table) (ei);
316 if (!shdr) {
317 return false;
318 }
319
320 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
321 int i;
322 for (i = 0; i < ehdr->e_shnum; ++i) {
323 switch (shdr->sh_type) {
324 case SHT_SYMTAB:
325 case SHT_DYNSYM:
326 {
327 Elf_W(Sym)* symtab = (Elf_W(Sym) *) ((char *) ei->u.mapped.image + shdr->sh_offset);
328 Elf_W(Sym)* symtab_end = (Elf_W(Sym) *) ((char *) symtab + shdr->sh_size);
329
330 char* strtab = elf_w (string_table) (ei, shdr->sh_link);
331 if (!strtab) {
332 continue;
333 }
334
335 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr->sh_offset, shdr->sh_type);
336
337 Elf_W(Sym)* sym;
338 for (sym = symtab;
339 sym < symtab_end;
340 sym = (Elf_W(Sym) *) ((char *) sym + shdr->sh_entsize)) {
341 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_shndx != SHN_UNDEF) {
342 Elf_W(Addr) val;
343 if (tdep_get_func_addr (as, sym->st_value, &val) < 0) {
344 continue;
345 }
346 if (sym->st_shndx != SHN_ABS) {
347 val += load_offset;
348 }
349 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym->st_info);
350 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym->st_size) {
351 char* str_name = strtab + sym->st_name;
352 if (str_name > (char*) ei->u.mapped.image + ei->u.mapped.size ||
353 str_name < strtab) {
354 // Malformed elf symbol table.
355 break;
356 }
357
358 // Make sure we don't try and read past the end of the image.
359 uintptr_t max_size = (uintptr_t) str_name - (uintptr_t) ei->u.mapped.image;
360 if (buf_len > max_size) {
361 buf_len = max_size;
362 }
363
364 strncpy (buf, str_name, buf_len);
365 // Ensure the string is nul terminated, it is assumed that
366 // sizeof(buf) >= buf_len + 1.
367 buf[buf_len] = '\0';
368 if (buf[0] == '\0') {
369 // Empty name, so keep checking the other symbol tables
370 // for a possible match.
371 break;
372 }
373 if (offp != NULL) {
374 *offp = ip - val;
375 }
376 return true;
377 }
378 }
379 }
380 break;
381 }
382
383 default:
384 break;
385 }
386 shdr = (Elf_W(Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
387 }
388 return false;
389 }
390
elf_w(get_load_offset_mapped)391 static bool elf_w (get_load_offset_mapped) (
392 struct elf_image *ei, unsigned long segbase, unsigned long mapoff, Elf_W(Addr)* load_offset) {
393 Elf_W(Ehdr) *ehdr = ei->u.mapped.image;
394 Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff);
395
396 int i;
397 for (i = 0; i < ehdr->e_phnum; ++i) {
398 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) {
399 *load_offset = segbase - phdr[i].p_vaddr;
400 return true;
401 }
402 }
403 return false;
404 }
405
elf_w(get_min_vaddr_mapped)406 static Elf_W(Addr) elf_w (get_min_vaddr_mapped) (struct elf_image *ei) {
407 Elf_W(Ehdr) *ehdr = ei->u.mapped.image;
408 Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff);
409 Elf_W(Addr) min_vaddr = ~0u;
410 int i;
411 for (i = 0; i < ehdr->e_phnum; ++i) {
412 if (phdr[i].p_type == PT_LOAD && phdr[i].p_vaddr < min_vaddr) {
413 min_vaddr = phdr[i].p_vaddr;
414 }
415 }
416 return min_vaddr;
417 }
418
419 // --------------------------------------------------------------------------
420
elf_w(lookup_symbol)421 static inline bool elf_w (lookup_symbol) (
422 unw_addr_space_t as, unw_word_t ip, struct elf_image *ei, Elf_W(Addr) load_offset,
423 char *buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) {
424 if (!ei->valid)
425 return false;
426
427 if (buf_len <= 1) {
428 Debug (1, "lookup_symbol called with a buffer too small to hold a name %zu\n", buf_len);
429 return false;
430 }
431
432 // Leave enough space for the nul terminator.
433 buf_len--;
434
435 if (ei->mapped) {
436 return elf_w (lookup_symbol_mapped) (as, ip, ei, load_offset, buf, buf_len, offp);
437 } else {
438 return elf_w (lookup_symbol_memory) (as, ip, ei, load_offset, buf, buf_len, offp, ehdr);
439 }
440 }
441
elf_w(get_load_offset)442 static bool elf_w (get_load_offset) (
443 struct elf_image* ei, unsigned long segbase, unsigned long mapoff,
444 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) {
445 if (ei->mapped) {
446 return elf_w (get_load_offset_mapped) (ei, segbase, mapoff, load_offset);
447 } else {
448 return elf_w (get_load_offset_memory) (ei, segbase, mapoff, ehdr, load_offset);
449 }
450 }
451
452 /* ANDROID support update. */
xz_alloc(void * p,size_t size)453 static void* xz_alloc(void* p, size_t size) {
454 return malloc(size);
455 }
456
xz_free(void * p,void * address)457 static void xz_free(void* p, void* address) {
458 free(address);
459 }
460
461 HIDDEN bool
elf_w(xz_decompress)462 elf_w (xz_decompress) (uint8_t* src, size_t src_size,
463 uint8_t** dst, size_t* dst_size) {
464 #if HAVE_LZMA
465 size_t src_offset = 0;
466 size_t dst_offset = 0;
467 size_t src_remaining;
468 size_t dst_remaining;
469 ISzAlloc alloc;
470 CXzUnpacker state;
471 ECoderStatus status;
472 alloc.Alloc = xz_alloc;
473 alloc.Free = xz_free;
474 XzUnpacker_Construct(&state, &alloc);
475 CrcGenerateTable();
476 Crc64GenerateTable();
477 *dst_size = 2 * src_size;
478 *dst = NULL;
479 do {
480 *dst_size *= 2;
481 *dst = realloc(*dst, *dst_size);
482 if (*dst == NULL) {
483 Debug (1, "LZMA decompression failed due to failed realloc.\n");
484 XzUnpacker_Free(&state);
485 return false;
486 }
487 src_remaining = src_size - src_offset;
488 dst_remaining = *dst_size - dst_offset;
489 int res = XzUnpacker_Code(&state,
490 *dst + dst_offset, &dst_remaining,
491 src + src_offset, &src_remaining,
492 CODER_FINISH_ANY, &status);
493 if (res != SZ_OK) {
494 Debug (1, "LZMA decompression failed with error %d\n", res);
495 free(*dst);
496 XzUnpacker_Free(&state);
497 return false;
498 }
499 src_offset += src_remaining;
500 dst_offset += dst_remaining;
501 } while (status == CODER_STATUS_NOT_FINISHED);
502 XzUnpacker_Free(&state);
503 if (!XzUnpacker_IsStreamWasFinished(&state)) {
504 Debug (1, "LZMA decompression failed due to incomplete stream.\n");
505 free(*dst);
506 return false;
507 }
508 *dst_size = dst_offset;
509 *dst = realloc(*dst, *dst_size);
510 return true;
511 #else
512 Debug (1, "Decompression failed - compiled without LZMA support.\n");
513 return false;
514 #endif // HAVE_LZMA
515 }
516
517 HIDDEN bool
elf_w(find_section_mapped)518 elf_w (find_section_mapped) (struct elf_image *ei, const char* name,
519 uint8_t** section, size_t* size, Elf_W(Addr)* vaddr) {
520 Elf_W (Ehdr) *ehdr = ei->u.mapped.image;
521 Elf_W (Shdr) *shdr;
522 char *strtab;
523 int i;
524
525 if (!ei->valid || !ei->mapped) {
526 return false;
527 }
528
529 shdr = elf_w (section_table) (ei);
530 if (!shdr) {
531 return false;
532 }
533
534 strtab = elf_w (string_table) (ei, ehdr->e_shstrndx);
535 if (!strtab) {
536 return false;
537 }
538
539 for (i = 0; i < ehdr->e_shnum; ++i) {
540 if (strcmp (strtab + shdr->sh_name, name) == 0) {
541 if (section != NULL && size != NULL) {
542 if (shdr->sh_offset + shdr->sh_size > ei->u.mapped.size) {
543 Debug (1, "section %s outside image? (0x%lu > 0x%lu)\n", name,
544 (unsigned long) (shdr->sh_offset + shdr->sh_size),
545 (unsigned long) ei->u.mapped.size);
546 return false;
547 }
548 *section = ((uint8_t *) ei->u.mapped.image) + shdr->sh_offset;
549 *size = shdr->sh_size;
550 }
551 if (vaddr != NULL) {
552 *vaddr = shdr->sh_addr;
553 }
554 return true;
555 }
556 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
557 }
558 return false;
559 }
560 /* ANDROID support update. */
561
562 // Find the ELF image that contains IP and return the procedure name from
563 // the symbol table that matches the IP.
elf_w(get_proc_name_in_image)564 HIDDEN bool elf_w (get_proc_name_in_image) (
565 unw_addr_space_t as, struct elf_image* ei, unsigned long segbase, unsigned long mapoff,
566 unw_word_t ip, char* buf, size_t buf_len, unw_word_t* offp) {
567 Elf_W(Ehdr) ehdr;
568 memset(&ehdr, 0, sizeof(ehdr));
569 Elf_W(Addr) load_offset;
570 if (!elf_w (get_load_offset) (ei, segbase, mapoff, &ehdr, &load_offset)) {
571 return false;
572 }
573
574 if (elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp, &ehdr) != 0) {
575 return true;
576 }
577
578 // If the ELF image doesn't contain a match, look up the symbol in
579 // the MiniDebugInfo.
580 if (ei->mapped && ei->mini_debug_info_data) {
581 struct elf_image mdi;
582 mdi.mapped = true;
583 mdi.u.mapped.image = ei->mini_debug_info_data;
584 mdi.u.mapped.size = ei->mini_debug_info_size;
585 mdi.valid = elf_w (valid_object_mapped) (&mdi);
586 // The ELF file might have been relocated after the debug
587 // information has been compresses and embedded.
588 ElfW(Addr) ei_text_address, mdi_text_address;
589 if (elf_w (find_section_mapped) (ei, ".text", NULL, NULL, &ei_text_address) &&
590 elf_w (find_section_mapped) (&mdi, ".text", NULL, NULL, &mdi_text_address)) {
591 load_offset += ei_text_address - mdi_text_address;
592 }
593 bool ret_val = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, buf_len, offp, &ehdr);
594 return ret_val;
595 }
596 return false;
597 }
598
elf_w(get_proc_name)599 HIDDEN bool elf_w (get_proc_name) (
600 unw_addr_space_t as, pid_t pid, unw_word_t ip, char* buf, size_t buf_len,
601 unw_word_t* offp, void* as_arg) {
602 unsigned long segbase, mapoff;
603 struct elf_image ei;
604
605 if (tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL, as_arg) < 0) {
606 return false;
607 }
608
609 return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp);
610 }
611
elf_w(get_load_base)612 HIDDEN bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base) {
613 if (!ei->valid) {
614 return false;
615 }
616
617 if (ei->mapped) {
618 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
619 Elf_W(Phdr)* phdr = (Elf_W(Phdr)*) ((char*) ei->u.mapped.image + ehdr->e_phoff);
620 int i;
621 for (i = 0; i < ehdr->e_phnum; ++i) {
622 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) {
623 *load_base = phdr[i].p_vaddr;
624 return true;
625 }
626 }
627 return false;
628 } else {
629 Elf_W(Ehdr) ehdr;
630 GET_EHDR_FIELD(ei, &ehdr, e_phnum, false);
631 GET_EHDR_FIELD(ei, &ehdr, e_phoff, false);
632 int i;
633 unw_word_t offset = ehdr.e_phoff;
634 for (i = 0; i < ehdr.e_phnum; ++i) {
635 Elf_W(Phdr) phdr;
636 GET_PHDR_FIELD(ei, offset, &phdr, p_type);
637 GET_PHDR_FIELD(ei, offset, &phdr, p_offset);
638 // Always use zero as the map offset for in memory maps.
639 // The dlopen of a shared library from an APK will result in a
640 // non-zero map offset which would mean we would never find the
641 // correct program header using the passed in map offset.
642 if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
643 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr);
644 *load_base = phdr.p_vaddr;
645 return true;
646 }
647 offset += sizeof(phdr);
648 }
649 return false;
650 }
651 return false;
652 }
653