• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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