Home | History | Annotate | Download | only in src
      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 // --------------------------------------------------------------------------
     37 // Functions to read elf data from memory.
     38 // --------------------------------------------------------------------------
     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 
    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 
    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 
    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 
    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 // --------------------------------------------------------------------------
    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 
    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 
    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 
    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 
    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 
    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
    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 
    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
    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.
    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 
    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 
    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