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