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