Home | History | Annotate | Download | only in Unwind
      1 //===------------------------- AddressSpace.hpp ---------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //
      9 // Abstracts accessing local vs remote address spaces.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef __ADDRESSSPACE_HPP__
     14 #define __ADDRESSSPACE_HPP__
     15 
     16 #include <stdint.h>
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 
     21 #if !_LIBUNWIND_IS_BAREMETAL
     22 #include <dlfcn.h>
     23 #if defined(__ANDROID__) && !__LP64__
     24 // dladdr only exits in API >= 8. Call to our my_dladdr in android/support for dynamic lookup
     25 #if __ANDROID_API__ < 8
     26 typedef struct {
     27     const char *dli_fname;  /* Pathname of shared object that contains address */
     28     void       *dli_fbase;  /* Address at which shared object is loaded */
     29     const char *dli_sname;  /* Name of nearest symbol with address lower than addr */
     30     void       *dli_saddr;  /* Exact address of symbol named in dli_sname */
     31 } Dl_info;
     32 #endif // __ANDROID_API__ >= 8
     33 extern "C" int my_dladdr(const void* addr, Dl_info *info);
     34 #define dladdr  my_dladdr
     35 #endif
     36 #endif
     37 
     38 #if __APPLE__
     39 #include <mach-o/getsect.h>
     40 namespace libunwind {
     41    bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
     42 }
     43 #endif
     44 
     45 #include "libunwind.h"
     46 #include "config.h"
     47 #include "dwarf2.h"
     48 #include "Registers.hpp"
     49 
     50 #if LIBCXXABI_ARM_EHABI
     51 #if __LINUX__
     52  // Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system.
     53  typedef long unsigned int *_Unwind_Ptr;
     54  extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr targetAddr, int *length);
     55  _Unwind_Ptr (*dl_unwind_find_exidx)(_Unwind_Ptr targetAddr, int *length) =
     56      __gnu_Unwind_Find_exidx;
     57 #else
     58  #include <link.h>
     59 #endif
     60 #endif  // LIBCXXABI_ARM_EHABI
     61 
     62 #if LIBCXXABI_ARM_EHABI && _LIBUNWIND_IS_BAREMETAL
     63 // When statically linked on bare-metal, the symbols for the EH table are looked
     64 // up without going through the dynamic loader.
     65 // TODO(jroelofs): since Newlib on arm-none-eabi doesn't
     66 //                 have dl_unwind_find_exidx...
     67 struct EHTEntry {
     68   uint32_t functionOffset;
     69   uint32_t unwindOpcodes;
     70 };
     71 extern EHTEntry __exidx_start;
     72 extern EHTEntry __exidx_end;
     73 #endif
     74 
     75 namespace libunwind {
     76 
     77 /// Used by findUnwindSections() to return info about needed sections.
     78 struct UnwindInfoSections {
     79 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
     80   uintptr_t       dso_base;
     81   uintptr_t       dwarf_section;
     82   uintptr_t       dwarf_section_length;
     83 #endif
     84 #if _LIBUNWIND_SUPPORT_DWARF_INDEX
     85   uintptr_t       dso_base;
     86   uintptr_t       dwarf_index_section;
     87   uintptr_t       dwarf_index_section_length;
     88 #endif
     89 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
     90   uintptr_t       dso_base;
     91   uintptr_t       compact_unwind_section;
     92   uintptr_t       compact_unwind_section_length;
     93 #endif
     94 #if LIBCXXABI_ARM_EHABI
     95   // No dso_base for ARM EHABI.
     96   uintptr_t       arm_section;
     97   uintptr_t       arm_section_length;
     98 #endif
     99 };
    100 
    101 
    102 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
    103 /// unwinding a thread in the same process.  The wrappers compile away,
    104 /// making local unwinds fast.
    105 class __attribute__((visibility("hidden"))) LocalAddressSpace {
    106 public:
    107 #if __LP64__
    108   typedef uint64_t pint_t;
    109   typedef int64_t  sint_t;
    110 #else
    111   typedef uint32_t pint_t;
    112   typedef int32_t  sint_t;
    113 #endif
    114   uint8_t         get8(pint_t addr) {
    115     uint8_t val;
    116     memcpy(&val, (void *)addr, sizeof(val));
    117     return val;
    118   }
    119   uint16_t         get16(pint_t addr) {
    120     uint16_t val;
    121     memcpy(&val, (void *)addr, sizeof(val));
    122     return val;
    123   }
    124   uint32_t         get32(pint_t addr) {
    125     uint32_t val;
    126     memcpy(&val, (void *)addr, sizeof(val));
    127     return val;
    128   }
    129   uint64_t         get64(pint_t addr) {
    130     uint64_t val;
    131     memcpy(&val, (void *)addr, sizeof(val));
    132     return val;
    133   }
    134   double           getDouble(pint_t addr) {
    135     double val;
    136     memcpy(&val, (void *)addr, sizeof(val));
    137     return val;
    138   }
    139   v128             getVector(pint_t addr) {
    140     v128 val;
    141     memcpy(&val, (void *)addr, sizeof(val));
    142     return val;
    143   }
    144   uintptr_t       getP(pint_t addr);
    145   static uint64_t getULEB128(pint_t &addr, pint_t end);
    146   static int64_t  getSLEB128(pint_t &addr, pint_t end);
    147 
    148   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
    149   bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
    150                         unw_word_t *offset);
    151   bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
    152   bool findOtherFDE(pint_t targetAddr, pint_t &fde);
    153 
    154   static LocalAddressSpace sThisAddressSpace;
    155 };
    156 
    157 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
    158 #if __LP64__
    159   return get64(addr);
    160 #else
    161   return get32(addr);
    162 #endif
    163 }
    164 
    165 /// Read a ULEB128 into a 64-bit word.
    166 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
    167   const uint8_t *p = (uint8_t *)addr;
    168   const uint8_t *pend = (uint8_t *)end;
    169   uint64_t result = 0;
    170   int bit = 0;
    171   do {
    172     uint64_t b;
    173 
    174     if (p == pend)
    175       _LIBUNWIND_ABORT("truncated uleb128 expression");
    176 
    177     b = *p & 0x7f;
    178 
    179     if (bit >= 64 || b << bit >> bit != b) {
    180       _LIBUNWIND_ABORT("malformed uleb128 expression");
    181     } else {
    182       result |= b << bit;
    183       bit += 7;
    184     }
    185   } while (*p++ >= 0x80);
    186   addr = (pint_t) p;
    187   return result;
    188 }
    189 
    190 /// Read a SLEB128 into a 64-bit word.
    191 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
    192   const uint8_t *p = (uint8_t *)addr;
    193   const uint8_t *pend = (uint8_t *)end;
    194   int64_t result = 0;
    195   int bit = 0;
    196   uint8_t byte;
    197   do {
    198     if (p == pend)
    199       _LIBUNWIND_ABORT("truncated sleb128 expression");
    200     byte = *p++;
    201     result |= ((byte & 0x7f) << bit);
    202     bit += 7;
    203   } while (byte & 0x80);
    204   // sign extend negative numbers
    205   if ((byte & 0x40) != 0)
    206     result |= (-1LL) << bit;
    207   addr = (pint_t) p;
    208   return result;
    209 }
    210 
    211 inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr,
    212                                                          pint_t end,
    213                                                          uint8_t encoding) {
    214   pint_t startAddr = addr;
    215   const uint8_t *p = (uint8_t *)addr;
    216   pint_t result;
    217 
    218   // first get value
    219   switch (encoding & 0x0F) {
    220   case DW_EH_PE_ptr:
    221     result = getP(addr);
    222     p += sizeof(pint_t);
    223     addr = (pint_t) p;
    224     break;
    225   case DW_EH_PE_uleb128:
    226     result = (pint_t)getULEB128(addr, end);
    227     break;
    228   case DW_EH_PE_udata2:
    229     result = get16(addr);
    230     p += 2;
    231     addr = (pint_t) p;
    232     break;
    233   case DW_EH_PE_udata4:
    234     result = get32(addr);
    235     p += 4;
    236     addr = (pint_t) p;
    237     break;
    238   case DW_EH_PE_udata8:
    239     result = (pint_t)get64(addr);
    240     p += 8;
    241     addr = (pint_t) p;
    242     break;
    243   case DW_EH_PE_sleb128:
    244     result = (pint_t)getSLEB128(addr, end);
    245     break;
    246   case DW_EH_PE_sdata2:
    247     // Sign extend from signed 16-bit value.
    248     result = (pint_t)(int16_t)get16(addr);
    249     p += 2;
    250     addr = (pint_t) p;
    251     break;
    252   case DW_EH_PE_sdata4:
    253     // Sign extend from signed 32-bit value.
    254     result = (pint_t)(int32_t)get32(addr);
    255     p += 4;
    256     addr = (pint_t) p;
    257     break;
    258   case DW_EH_PE_sdata8:
    259     result = (pint_t)get64(addr);
    260     p += 8;
    261     addr = (pint_t) p;
    262     break;
    263   default:
    264     _LIBUNWIND_ABORT("unknown pointer encoding");
    265   }
    266 
    267   // then add relative offset
    268   switch (encoding & 0x70) {
    269   case DW_EH_PE_absptr:
    270     // do nothing
    271     break;
    272   case DW_EH_PE_pcrel:
    273     result += startAddr;
    274     break;
    275   case DW_EH_PE_textrel:
    276     _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
    277     break;
    278   case DW_EH_PE_datarel:
    279     _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported");
    280     break;
    281   case DW_EH_PE_funcrel:
    282     _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
    283     break;
    284   case DW_EH_PE_aligned:
    285     _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
    286     break;
    287   default:
    288     _LIBUNWIND_ABORT("unknown pointer encoding");
    289     break;
    290   }
    291 
    292   if (encoding & DW_EH_PE_indirect)
    293     result = getP(result);
    294 
    295   return result;
    296 }
    297 
    298 #if __APPLE__
    299   struct dyld_unwind_sections
    300   {
    301     const struct mach_header*   mh;
    302     const void*                 dwarf_section;
    303     uintptr_t                   dwarf_section_length;
    304     const void*                 compact_unwind_section;
    305     uintptr_t                   compact_unwind_section_length;
    306   };
    307   #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
    308                                  && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
    309       || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
    310     // In 10.7.0 or later, libSystem.dylib implements this function.
    311     extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
    312   #else
    313     // In 10.6.x and earlier, we need to implement this functionality.
    314     static inline bool _dyld_find_unwind_sections(void* addr,
    315                                                     dyld_unwind_sections* info) {
    316       // Find mach-o image containing address.
    317       Dl_info dlinfo;
    318       if (!dladdr(addr, &dlinfo))
    319         return false;
    320       const mach_header *mh = (const mach_header *)dlinfo.dli_saddr;
    321 
    322       // Find dwarf unwind section in that image.
    323       unsigned long size;
    324       const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size);
    325       if (!p)
    326         return false;
    327 
    328       // Fill in return struct.
    329       info->mh = mh;
    330       info->dwarf_section = p;
    331       info->dwarf_section_length = size;
    332       info->compact_unwind_section = 0;
    333       info->compact_unwind_section_length = 0;
    334 
    335       return true;
    336     }
    337   #endif
    338 #endif
    339 
    340 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
    341                                                   UnwindInfoSections &info) {
    342 #if __APPLE__
    343   dyld_unwind_sections dyldInfo;
    344   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
    345     info.dso_base                      = (uintptr_t)dyldInfo.mh;
    346  #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
    347     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
    348     info.dwarf_section_length          = dyldInfo.dwarf_section_length;
    349  #endif
    350     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
    351     info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
    352     return true;
    353   }
    354 #elif LIBCXXABI_ARM_EHABI
    355  #if !_LIBUNWIND_IS_BAREMETAL
    356   int length = 0;
    357   info.arm_section = (uintptr_t) dl_unwind_find_exidx(
    358       (_Unwind_Ptr) targetAddr, &length);
    359   info.arm_section_length = length;
    360  #else
    361   // Bare metal, statically linked
    362   info.arm_section =        (uintptr_t)(&__exidx_start);
    363   info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
    364  #endif
    365   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n",
    366                              info.arm_section, info.arm_section_length);
    367   if (info.arm_section && info.arm_section_length)
    368     return true;
    369 #endif
    370 
    371   return false;
    372 }
    373 
    374 
    375 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
    376 #if __APPLE__
    377   return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
    378 #else
    379   // TO DO: if OS has way to dynamically register FDEs, check that.
    380   return false;
    381 #endif
    382 }
    383 
    384 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
    385                                                 size_t bufLen,
    386                                                 unw_word_t *offset) {
    387 #if !_LIBUNWIND_IS_BAREMETAL
    388   Dl_info dyldInfo;
    389   if (dladdr((void *)addr, &dyldInfo)) {
    390     if (dyldInfo.dli_sname != NULL) {
    391       strlcpy(buf, dyldInfo.dli_sname, bufLen);
    392       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
    393       return true;
    394     }
    395   }
    396 #endif
    397   return false;
    398 }
    399 
    400 
    401 
    402 #if UNW_REMOTE
    403 
    404 /// OtherAddressSpace is used as a template parameter to UnwindCursor when
    405 /// unwinding a thread in the another process.  The other process can be a
    406 /// different endianness and a different pointer size which is handled by
    407 /// the P template parameter.
    408 template <typename P>
    409 class OtherAddressSpace {
    410 public:
    411   OtherAddressSpace(task_t task) : fTask(task) {}
    412 
    413   typedef typename P::uint_t pint_t;
    414 
    415   uint8_t   get8(pint_t addr);
    416   uint16_t  get16(pint_t addr);
    417   uint32_t  get32(pint_t addr);
    418   uint64_t  get64(pint_t addr);
    419   pint_t    getP(pint_t addr);
    420   uint64_t  getULEB128(pint_t &addr, pint_t end);
    421   int64_t   getSLEB128(pint_t &addr, pint_t end);
    422   pint_t    getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
    423   bool      findFunctionName(pint_t addr, char *buf, size_t bufLen,
    424                         unw_word_t *offset);
    425   bool      findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
    426   bool      findOtherFDE(pint_t targetAddr, pint_t &fde);
    427 private:
    428   void *localCopy(pint_t addr);
    429 
    430   task_t fTask;
    431 };
    432 
    433 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
    434   return *((uint8_t *)localCopy(addr));
    435 }
    436 
    437 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
    438   return P::E::get16(*(uint16_t *)localCopy(addr));
    439 }
    440 
    441 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
    442   return P::E::get32(*(uint32_t *)localCopy(addr));
    443 }
    444 
    445 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
    446   return P::E::get64(*(uint64_t *)localCopy(addr));
    447 }
    448 
    449 template <typename P>
    450 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
    451   return P::getP(*(uint64_t *)localCopy(addr));
    452 }
    453 
    454 template <typename P>
    455 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
    456   uintptr_t size = (end - addr);
    457   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
    458   LocalAddressSpace::pint_t sladdr = laddr;
    459   uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
    460   addr += (laddr - sladdr);
    461   return result;
    462 }
    463 
    464 template <typename P>
    465 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
    466   uintptr_t size = (end - addr);
    467   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
    468   LocalAddressSpace::pint_t sladdr = laddr;
    469   uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
    470   addr += (laddr - sladdr);
    471   return result;
    472 }
    473 
    474 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
    475   // FIX ME
    476 }
    477 
    478 template <typename P>
    479 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
    480                                             size_t bufLen, unw_word_t *offset) {
    481   // FIX ME
    482 }
    483 
    484 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
    485 /// libunwind.h points to.
    486 struct unw_addr_space {
    487   cpu_type_t cpuType;
    488   task_t taskPort;
    489 };
    490 
    491 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
    492 /// to when examining
    493 /// a 32-bit intel process.
    494 struct unw_addr_space_i386 : public unw_addr_space {
    495   unw_addr_space_i386(task_t task) : oas(task) {}
    496   OtherAddressSpace<Pointer32<LittleEndian> > oas;
    497 };
    498 
    499 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
    500 /// points to when examining
    501 /// a 64-bit intel process.
    502 struct unw_addr_space_x86_64 : public unw_addr_space {
    503   unw_addr_space_x86_64(task_t task) : oas(task) {}
    504   OtherAddressSpace<Pointer64<LittleEndian> > oas;
    505 };
    506 
    507 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
    508 /// to when examining
    509 /// a 32-bit PowerPC process.
    510 struct unw_addr_space_ppc : public unw_addr_space {
    511   unw_addr_space_ppc(task_t task) : oas(task) {}
    512   OtherAddressSpace<Pointer32<BigEndian> > oas;
    513 };
    514 
    515 #endif // UNW_REMOTE
    516 
    517 } // namespace libunwind
    518 
    519 #endif // __ADDRESSSPACE_HPP__
    520