Home | History | Annotate | Download | only in src
      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 !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
     22 #include <dlfcn.h>
     23 #endif
     24 
     25 #ifdef __APPLE__
     26 #include <mach-o/getsect.h>
     27 namespace libunwind {
     28    bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
     29 }
     30 #endif
     31 
     32 #include "libunwind.h"
     33 #include "config.h"
     34 #include "dwarf2.h"
     35 #include "EHHeaderParser.hpp"
     36 #include "Registers.hpp"
     37 
     38 #ifdef __APPLE__
     39 
     40   struct dyld_unwind_sections
     41   {
     42     const struct mach_header*   mh;
     43     const void*                 dwarf_section;
     44     uintptr_t                   dwarf_section_length;
     45     const void*                 compact_unwind_section;
     46     uintptr_t                   compact_unwind_section_length;
     47   };
     48   #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
     49                                  && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
     50       || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
     51     // In 10.7.0 or later, libSystem.dylib implements this function.
     52     extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
     53   #else
     54     // In 10.6.x and earlier, we need to implement this functionality. Note
     55     // that this requires a newer version of libmacho (from cctools) than is
     56     // present in libSystem on 10.6.x (for getsectiondata).
     57     static inline bool _dyld_find_unwind_sections(void* addr,
     58                                                     dyld_unwind_sections* info) {
     59       // Find mach-o image containing address.
     60       Dl_info dlinfo;
     61       if (!dladdr(addr, &dlinfo))
     62         return false;
     63 #if __LP64__
     64       const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
     65 #else
     66       const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
     67 #endif
     68 
     69       // Initialize the return struct
     70       info->mh = (const struct mach_header *)mh;
     71       info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
     72       info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
     73 
     74       if (!info->dwarf_section) {
     75         info->dwarf_section_length = 0;
     76       }
     77 
     78       if (!info->compact_unwind_section) {
     79         info->compact_unwind_section_length = 0;
     80       }
     81 
     82       return true;
     83     }
     84   #endif
     85 
     86 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
     87 
     88 // When statically linked on bare-metal, the symbols for the EH table are looked
     89 // up without going through the dynamic loader.
     90 extern char __exidx_start;
     91 extern char __exidx_end;
     92 
     93 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
     94 
     95 // ELF-based systems may use dl_iterate_phdr() to access sections
     96 // containing unwinding information. The ElfW() macro for pointer-size
     97 // independent ELF header traversal is not provided by <link.h> on some
     98 // systems (e.g., FreeBSD). On these systems the data structures are
     99 // just called Elf_XXX. Define ElfW() locally.
    100 #ifndef _WIN32
    101 #include <link.h>
    102 #else
    103 #include <windows.h>
    104 #include <psapi.h>
    105 #endif
    106 #if !defined(ElfW)
    107 #define ElfW(type) Elf_##type
    108 #endif
    109 
    110 #endif
    111 
    112 namespace libunwind {
    113 
    114 /// Used by findUnwindSections() to return info about needed sections.
    115 struct UnwindInfoSections {
    116 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) ||       \
    117     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
    118   // No dso_base for ARM EHABI.
    119   uintptr_t       dso_base;
    120 #endif
    121 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
    122   uintptr_t       dwarf_section;
    123   uintptr_t       dwarf_section_length;
    124 #endif
    125 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
    126   uintptr_t       dwarf_index_section;
    127   uintptr_t       dwarf_index_section_length;
    128 #endif
    129 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
    130   uintptr_t       compact_unwind_section;
    131   uintptr_t       compact_unwind_section_length;
    132 #endif
    133 #if defined(_LIBUNWIND_ARM_EHABI)
    134   uintptr_t       arm_section;
    135   uintptr_t       arm_section_length;
    136 #endif
    137 };
    138 
    139 
    140 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
    141 /// unwinding a thread in the same process.  The wrappers compile away,
    142 /// making local unwinds fast.
    143 class __attribute__((visibility("hidden"))) LocalAddressSpace {
    144 public:
    145   typedef uintptr_t pint_t;
    146   typedef intptr_t  sint_t;
    147   uint8_t         get8(pint_t addr) {
    148     uint8_t val;
    149     memcpy(&val, (void *)addr, sizeof(val));
    150     return val;
    151   }
    152   uint16_t         get16(pint_t addr) {
    153     uint16_t val;
    154     memcpy(&val, (void *)addr, sizeof(val));
    155     return val;
    156   }
    157   uint32_t         get32(pint_t addr) {
    158     uint32_t val;
    159     memcpy(&val, (void *)addr, sizeof(val));
    160     return val;
    161   }
    162   uint64_t         get64(pint_t addr) {
    163     uint64_t val;
    164     memcpy(&val, (void *)addr, sizeof(val));
    165     return val;
    166   }
    167   double           getDouble(pint_t addr) {
    168     double val;
    169     memcpy(&val, (void *)addr, sizeof(val));
    170     return val;
    171   }
    172   v128             getVector(pint_t addr) {
    173     v128 val;
    174     memcpy(&val, (void *)addr, sizeof(val));
    175     return val;
    176   }
    177   uintptr_t       getP(pint_t addr);
    178   static uint64_t getULEB128(pint_t &addr, pint_t end);
    179   static int64_t  getSLEB128(pint_t &addr, pint_t end);
    180 
    181   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
    182                      pint_t datarelBase = 0);
    183   bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
    184                         unw_word_t *offset);
    185   bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
    186   bool findOtherFDE(pint_t targetAddr, pint_t &fde);
    187 
    188   static LocalAddressSpace sThisAddressSpace;
    189 };
    190 
    191 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
    192 #if __SIZEOF_POINTER__ == 8
    193   return get64(addr);
    194 #else
    195   return get32(addr);
    196 #endif
    197 }
    198 
    199 /// Read a ULEB128 into a 64-bit word.
    200 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
    201   const uint8_t *p = (uint8_t *)addr;
    202   const uint8_t *pend = (uint8_t *)end;
    203   uint64_t result = 0;
    204   int bit = 0;
    205   do {
    206     uint64_t b;
    207 
    208     if (p == pend)
    209       _LIBUNWIND_ABORT("truncated uleb128 expression");
    210 
    211     b = *p & 0x7f;
    212 
    213     if (bit >= 64 || b << bit >> bit != b) {
    214       _LIBUNWIND_ABORT("malformed uleb128 expression");
    215     } else {
    216       result |= b << bit;
    217       bit += 7;
    218     }
    219   } while (*p++ >= 0x80);
    220   addr = (pint_t) p;
    221   return result;
    222 }
    223 
    224 /// Read a SLEB128 into a 64-bit word.
    225 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
    226   const uint8_t *p = (uint8_t *)addr;
    227   const uint8_t *pend = (uint8_t *)end;
    228   int64_t result = 0;
    229   int bit = 0;
    230   uint8_t byte;
    231   do {
    232     if (p == pend)
    233       _LIBUNWIND_ABORT("truncated sleb128 expression");
    234     byte = *p++;
    235     result |= ((byte & 0x7f) << bit);
    236     bit += 7;
    237   } while (byte & 0x80);
    238   // sign extend negative numbers
    239   if ((byte & 0x40) != 0)
    240     result |= (-1ULL) << bit;
    241   addr = (pint_t) p;
    242   return result;
    243 }
    244 
    245 inline LocalAddressSpace::pint_t
    246 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
    247                                pint_t datarelBase) {
    248   pint_t startAddr = addr;
    249   const uint8_t *p = (uint8_t *)addr;
    250   pint_t result;
    251 
    252   // first get value
    253   switch (encoding & 0x0F) {
    254   case DW_EH_PE_ptr:
    255     result = getP(addr);
    256     p += sizeof(pint_t);
    257     addr = (pint_t) p;
    258     break;
    259   case DW_EH_PE_uleb128:
    260     result = (pint_t)getULEB128(addr, end);
    261     break;
    262   case DW_EH_PE_udata2:
    263     result = get16(addr);
    264     p += 2;
    265     addr = (pint_t) p;
    266     break;
    267   case DW_EH_PE_udata4:
    268     result = get32(addr);
    269     p += 4;
    270     addr = (pint_t) p;
    271     break;
    272   case DW_EH_PE_udata8:
    273     result = (pint_t)get64(addr);
    274     p += 8;
    275     addr = (pint_t) p;
    276     break;
    277   case DW_EH_PE_sleb128:
    278     result = (pint_t)getSLEB128(addr, end);
    279     break;
    280   case DW_EH_PE_sdata2:
    281     // Sign extend from signed 16-bit value.
    282     result = (pint_t)(int16_t)get16(addr);
    283     p += 2;
    284     addr = (pint_t) p;
    285     break;
    286   case DW_EH_PE_sdata4:
    287     // Sign extend from signed 32-bit value.
    288     result = (pint_t)(int32_t)get32(addr);
    289     p += 4;
    290     addr = (pint_t) p;
    291     break;
    292   case DW_EH_PE_sdata8:
    293     result = (pint_t)get64(addr);
    294     p += 8;
    295     addr = (pint_t) p;
    296     break;
    297   default:
    298     _LIBUNWIND_ABORT("unknown pointer encoding");
    299   }
    300 
    301   // then add relative offset
    302   switch (encoding & 0x70) {
    303   case DW_EH_PE_absptr:
    304     // do nothing
    305     break;
    306   case DW_EH_PE_pcrel:
    307     result += startAddr;
    308     break;
    309   case DW_EH_PE_textrel:
    310     _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
    311     break;
    312   case DW_EH_PE_datarel:
    313     // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
    314     // default value of 0, and we abort in the event that someone calls this
    315     // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
    316     if (datarelBase == 0)
    317       _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
    318     result += datarelBase;
    319     break;
    320   case DW_EH_PE_funcrel:
    321     _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
    322     break;
    323   case DW_EH_PE_aligned:
    324     _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
    325     break;
    326   default:
    327     _LIBUNWIND_ABORT("unknown pointer encoding");
    328     break;
    329   }
    330 
    331   if (encoding & DW_EH_PE_indirect)
    332     result = getP(result);
    333 
    334   return result;
    335 }
    336 
    337 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
    338                                                   UnwindInfoSections &info) {
    339 #ifdef __APPLE__
    340   dyld_unwind_sections dyldInfo;
    341   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
    342     info.dso_base                      = (uintptr_t)dyldInfo.mh;
    343  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
    344     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
    345     info.dwarf_section_length          = dyldInfo.dwarf_section_length;
    346  #endif
    347     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
    348     info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
    349     return true;
    350   }
    351 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
    352   // Bare metal is statically linked, so no need to ask the dynamic loader
    353   info.arm_section =        (uintptr_t)(&__exidx_start);
    354   info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
    355   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x",
    356                              info.arm_section, info.arm_section_length);
    357   if (info.arm_section && info.arm_section_length)
    358     return true;
    359 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
    360   HMODULE mods[1024];
    361   HANDLE process = GetCurrentProcess();
    362   DWORD needed;
    363 
    364   if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
    365     return false;
    366 
    367   for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
    368     PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
    369     PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
    370     PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
    371     PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
    372     bool found_obj = false;
    373     bool found_hdr = false;
    374 
    375     info.dso_base = (uintptr_t)mods[i];
    376     for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
    377       uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
    378       uintptr_t end = begin + pish->Misc.VirtualSize;
    379       if (!strncmp((const char *)pish->Name, ".text",
    380                    IMAGE_SIZEOF_SHORT_NAME)) {
    381         if (targetAddr >= begin && targetAddr < end)
    382           found_obj = true;
    383       } else if (!strncmp((const char *)pish->Name, ".eh_frame",
    384                           IMAGE_SIZEOF_SHORT_NAME)) {
    385         info.dwarf_section = begin;
    386         info.dwarf_section_length = pish->Misc.VirtualSize;
    387         found_hdr = true;
    388       }
    389       if (found_obj && found_hdr)
    390         return true;
    391     }
    392   }
    393   return false;
    394 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) &&                  \
    395     (__ANDROID_API__ < 21)
    396   int length = 0;
    397   info.arm_section =
    398       (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
    399   info.arm_section_length = (uintptr_t)length;
    400   if (info.arm_section && info.arm_section_length)
    401     return true;
    402 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
    403   struct dl_iterate_cb_data {
    404     LocalAddressSpace *addressSpace;
    405     UnwindInfoSections *sects;
    406     uintptr_t targetAddr;
    407   };
    408 
    409   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
    410   int found = dl_iterate_phdr(
    411       [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
    412         auto cbdata = static_cast<dl_iterate_cb_data *>(data);
    413         bool found_obj = false;
    414         bool found_hdr = false;
    415 
    416         assert(cbdata);
    417         assert(cbdata->sects);
    418 
    419         if (cbdata->targetAddr < pinfo->dlpi_addr) {
    420           return false;
    421         }
    422 
    423 #if !defined(Elf_Half)
    424         typedef ElfW(Half) Elf_Half;
    425 #endif
    426 #if !defined(Elf_Phdr)
    427         typedef ElfW(Phdr) Elf_Phdr;
    428 #endif
    429 #if !defined(Elf_Addr) && defined(__ANDROID__)
    430         typedef ElfW(Addr) Elf_Addr;
    431 #endif
    432 
    433  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
    434   #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
    435    #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
    436   #endif
    437         size_t object_length;
    438 #if defined(__ANDROID__)
    439         Elf_Addr image_base =
    440             pinfo->dlpi_phnum
    441                 ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
    442                       reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
    443                           ->p_offset
    444                 : 0;
    445 #endif
    446 
    447         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
    448           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
    449           if (phdr->p_type == PT_LOAD) {
    450             uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
    451 #if defined(__ANDROID__)
    452             if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
    453               begin = begin + image_base;
    454 #endif
    455             uintptr_t end = begin + phdr->p_memsz;
    456             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
    457               cbdata->sects->dso_base = begin;
    458               object_length = phdr->p_memsz;
    459               found_obj = true;
    460             }
    461           } else if (phdr->p_type == PT_GNU_EH_FRAME) {
    462             EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
    463             uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
    464 #if defined(__ANDROID__)
    465             if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
    466               eh_frame_hdr_start = eh_frame_hdr_start + image_base;
    467 #endif
    468             cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
    469             cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
    470             EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
    471                 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
    472                 hdrInfo);
    473             cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
    474             found_hdr = true;
    475           }
    476         }
    477 
    478         if (found_obj && found_hdr) {
    479           cbdata->sects->dwarf_section_length = object_length;
    480           return true;
    481         } else {
    482           return false;
    483         }
    484  #else // defined(_LIBUNWIND_ARM_EHABI)
    485         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
    486           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
    487           if (phdr->p_type == PT_LOAD) {
    488             uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
    489             uintptr_t end = begin + phdr->p_memsz;
    490             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
    491               found_obj = true;
    492           } else if (phdr->p_type == PT_ARM_EXIDX) {
    493             uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
    494             cbdata->sects->arm_section = exidx_start;
    495             cbdata->sects->arm_section_length = phdr->p_memsz;
    496             found_hdr = true;
    497           }
    498         }
    499         return found_obj && found_hdr;
    500  #endif
    501       },
    502       &cb_data);
    503   return static_cast<bool>(found);
    504 #endif
    505 
    506   return false;
    507 }
    508 
    509 
    510 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
    511 #ifdef __APPLE__
    512   return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
    513 #else
    514   // TO DO: if OS has way to dynamically register FDEs, check that.
    515   (void)targetAddr;
    516   (void)fde;
    517   return false;
    518 #endif
    519 }
    520 
    521 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
    522                                                 size_t bufLen,
    523                                                 unw_word_t *offset) {
    524 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
    525   Dl_info dyldInfo;
    526   if (dladdr((void *)addr, &dyldInfo)) {
    527     if (dyldInfo.dli_sname != NULL) {
    528       snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
    529       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
    530       return true;
    531     }
    532   }
    533 #endif
    534   return false;
    535 }
    536 
    537 
    538 
    539 #ifdef UNW_REMOTE
    540 
    541 /// RemoteAddressSpace is used as a template parameter to UnwindCursor when
    542 /// unwinding a thread in the another process.  The other process can be a
    543 /// different endianness and a different pointer size which is handled by
    544 /// the P template parameter.
    545 template <typename P>
    546 class RemoteAddressSpace {
    547 public:
    548   RemoteAddressSpace(task_t task) : fTask(task) {}
    549 
    550   typedef typename P::uint_t pint_t;
    551 
    552   uint8_t   get8(pint_t addr);
    553   uint16_t  get16(pint_t addr);
    554   uint32_t  get32(pint_t addr);
    555   uint64_t  get64(pint_t addr);
    556   pint_t    getP(pint_t addr);
    557   uint64_t  getULEB128(pint_t &addr, pint_t end);
    558   int64_t   getSLEB128(pint_t &addr, pint_t end);
    559   pint_t    getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
    560                         pint_t datarelBase = 0);
    561   bool      findFunctionName(pint_t addr, char *buf, size_t bufLen,
    562                         unw_word_t *offset);
    563   bool      findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
    564   bool      findOtherFDE(pint_t targetAddr, pint_t &fde);
    565 private:
    566   void *localCopy(pint_t addr);
    567 
    568   task_t fTask;
    569 };
    570 
    571 template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) {
    572   return *((uint8_t *)localCopy(addr));
    573 }
    574 
    575 template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) {
    576   return P::E::get16(*(uint16_t *)localCopy(addr));
    577 }
    578 
    579 template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) {
    580   return P::E::get32(*(uint32_t *)localCopy(addr));
    581 }
    582 
    583 template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) {
    584   return P::E::get64(*(uint64_t *)localCopy(addr));
    585 }
    586 
    587 template <typename P>
    588 typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) {
    589   return P::getP(*(uint64_t *)localCopy(addr));
    590 }
    591 
    592 template <typename P>
    593 uint64_t RemoteAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
    594   uintptr_t size = (end - addr);
    595   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
    596   LocalAddressSpace::pint_t sladdr = laddr;
    597   uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
    598   addr += (laddr - sladdr);
    599   return result;
    600 }
    601 
    602 template <typename P>
    603 int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
    604   uintptr_t size = (end - addr);
    605   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
    606   LocalAddressSpace::pint_t sladdr = laddr;
    607   uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
    608   addr += (laddr - sladdr);
    609   return result;
    610 }
    611 
    612 template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
    613   // FIX ME
    614 }
    615 
    616 template <typename P>
    617 bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
    618                                              size_t bufLen,
    619                                              unw_word_t *offset) {
    620   // FIX ME
    621 }
    622 
    623 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
    624 /// libunwind.h points to.
    625 struct unw_addr_space {
    626   cpu_type_t cpuType;
    627   task_t taskPort;
    628 };
    629 
    630 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
    631 /// to when examining
    632 /// a 32-bit intel process.
    633 struct unw_addr_space_i386 : public unw_addr_space {
    634   unw_addr_space_i386(task_t task) : oas(task) {}
    635   RemoteAddressSpace<Pointer32<LittleEndian>> oas;
    636 };
    637 
    638 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
    639 /// points to when examining
    640 /// a 64-bit intel process.
    641 struct unw_addr_space_x86_64 : public unw_addr_space {
    642   unw_addr_space_x86_64(task_t task) : oas(task) {}
    643   RemoteAddressSpace<Pointer64<LittleEndian>> oas;
    644 };
    645 
    646 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
    647 /// to when examining
    648 /// a 32-bit PowerPC process.
    649 struct unw_addr_space_ppc : public unw_addr_space {
    650   unw_addr_space_ppc(task_t task) : oas(task) {}
    651   RemoteAddressSpace<Pointer32<BigEndian>> oas;
    652 };
    653 
    654 #endif // UNW_REMOTE
    655 
    656 } // namespace libunwind
    657 
    658 #endif // __ADDRESSSPACE_HPP__
    659