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 #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 // --------------------------------------------------------------------------
     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 
    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 
    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 
    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 
    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 // --------------------------------------------------------------------------
    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 
    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 
    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 
    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 
    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 
    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 
    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. */
    453 static void* xz_alloc(void* p, size_t size) {
    454   return malloc(size);
    455 }
    456 
    457 static void xz_free(void* p, void* address) {
    458   free(address);
    459 }
    460 
    461 HIDDEN bool
    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
    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.
    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 
    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 
    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