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 #ifdef __LP64__
146   typedef uint64_t pint_t;
147   typedef int64_t  sint_t;
148 #else
149   typedef uint32_t pint_t;
150   typedef int32_t  sint_t;
151 #endif
152   uint8_t         get8(pint_t addr) {
153     uint8_t val;
154     memcpy(&val, (void *)addr, sizeof(val));
155     return val;
156   }
157   uint16_t         get16(pint_t addr) {
158     uint16_t val;
159     memcpy(&val, (void *)addr, sizeof(val));
160     return val;
161   }
162   uint32_t         get32(pint_t addr) {
163     uint32_t val;
164     memcpy(&val, (void *)addr, sizeof(val));
165     return val;
166   }
167   uint64_t         get64(pint_t addr) {
168     uint64_t val;
169     memcpy(&val, (void *)addr, sizeof(val));
170     return val;
171   }
172   double           getDouble(pint_t addr) {
173     double val;
174     memcpy(&val, (void *)addr, sizeof(val));
175     return val;
176   }
177   v128             getVector(pint_t addr) {
178     v128 val;
179     memcpy(&val, (void *)addr, sizeof(val));
180     return val;
181   }
182   uintptr_t       getP(pint_t addr);
183   static uint64_t getULEB128(pint_t &addr, pint_t end);
184   static int64_t  getSLEB128(pint_t &addr, pint_t end);
185 
186   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
187                      pint_t datarelBase = 0);
188   bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
189                         unw_word_t *offset);
190   bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
191   bool findOtherFDE(pint_t targetAddr, pint_t &fde);
192 
193   static LocalAddressSpace sThisAddressSpace;
194 };
195 
196 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
197 #ifdef __LP64__
198   return get64(addr);
199 #else
200   return get32(addr);
201 #endif
202 }
203 
204 /// Read a ULEB128 into a 64-bit word.
205 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
206   const uint8_t *p = (uint8_t *)addr;
207   const uint8_t *pend = (uint8_t *)end;
208   uint64_t result = 0;
209   int bit = 0;
210   do {
211     uint64_t b;
212 
213     if (p == pend)
214       _LIBUNWIND_ABORT("truncated uleb128 expression");
215 
216     b = *p & 0x7f;
217 
218     if (bit >= 64 || b << bit >> bit != b) {
219       _LIBUNWIND_ABORT("malformed uleb128 expression");
220     } else {
221       result |= b << bit;
222       bit += 7;
223     }
224   } while (*p++ >= 0x80);
225   addr = (pint_t) p;
226   return result;
227 }
228 
229 /// Read a SLEB128 into a 64-bit word.
230 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
231   const uint8_t *p = (uint8_t *)addr;
232   const uint8_t *pend = (uint8_t *)end;
233   int64_t result = 0;
234   int bit = 0;
235   uint8_t byte;
236   do {
237     if (p == pend)
238       _LIBUNWIND_ABORT("truncated sleb128 expression");
239     byte = *p++;
240     result |= ((byte & 0x7f) << bit);
241     bit += 7;
242   } while (byte & 0x80);
243   // sign extend negative numbers
244   if ((byte & 0x40) != 0)
245     result |= (-1ULL) << bit;
246   addr = (pint_t) p;
247   return result;
248 }
249 
250 inline LocalAddressSpace::pint_t
251 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
252                                pint_t datarelBase) {
253   pint_t startAddr = addr;
254   const uint8_t *p = (uint8_t *)addr;
255   pint_t result;
256 
257   // first get value
258   switch (encoding & 0x0F) {
259   case DW_EH_PE_ptr:
260     result = getP(addr);
261     p += sizeof(pint_t);
262     addr = (pint_t) p;
263     break;
264   case DW_EH_PE_uleb128:
265     result = (pint_t)getULEB128(addr, end);
266     break;
267   case DW_EH_PE_udata2:
268     result = get16(addr);
269     p += 2;
270     addr = (pint_t) p;
271     break;
272   case DW_EH_PE_udata4:
273     result = get32(addr);
274     p += 4;
275     addr = (pint_t) p;
276     break;
277   case DW_EH_PE_udata8:
278     result = (pint_t)get64(addr);
279     p += 8;
280     addr = (pint_t) p;
281     break;
282   case DW_EH_PE_sleb128:
283     result = (pint_t)getSLEB128(addr, end);
284     break;
285   case DW_EH_PE_sdata2:
286     // Sign extend from signed 16-bit value.
287     result = (pint_t)(int16_t)get16(addr);
288     p += 2;
289     addr = (pint_t) p;
290     break;
291   case DW_EH_PE_sdata4:
292     // Sign extend from signed 32-bit value.
293     result = (pint_t)(int32_t)get32(addr);
294     p += 4;
295     addr = (pint_t) p;
296     break;
297   case DW_EH_PE_sdata8:
298     result = (pint_t)get64(addr);
299     p += 8;
300     addr = (pint_t) p;
301     break;
302   default:
303     _LIBUNWIND_ABORT("unknown pointer encoding");
304   }
305 
306   // then add relative offset
307   switch (encoding & 0x70) {
308   case DW_EH_PE_absptr:
309     // do nothing
310     break;
311   case DW_EH_PE_pcrel:
312     result += startAddr;
313     break;
314   case DW_EH_PE_textrel:
315     _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
316     break;
317   case DW_EH_PE_datarel:
318     // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
319     // default value of 0, and we abort in the event that someone calls this
320     // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
321     if (datarelBase == 0)
322       _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
323     result += datarelBase;
324     break;
325   case DW_EH_PE_funcrel:
326     _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
327     break;
328   case DW_EH_PE_aligned:
329     _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
330     break;
331   default:
332     _LIBUNWIND_ABORT("unknown pointer encoding");
333     break;
334   }
335 
336   if (encoding & DW_EH_PE_indirect)
337     result = getP(result);
338 
339   return result;
340 }
341 
342 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
343                                                   UnwindInfoSections &info) {
344 #ifdef __APPLE__
345   dyld_unwind_sections dyldInfo;
346   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
347     info.dso_base                      = (uintptr_t)dyldInfo.mh;
348  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
349     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
350     info.dwarf_section_length          = dyldInfo.dwarf_section_length;
351  #endif
352     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
353     info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
354     return true;
355   }
356 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
357   // Bare metal is statically linked, so no need to ask the dynamic loader
358   info.arm_section =        (uintptr_t)(&__exidx_start);
359   info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
360   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x",
361                              info.arm_section, info.arm_section_length);
362   if (info.arm_section && info.arm_section_length)
363     return true;
364 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
365   HMODULE mods[1024];
366   HANDLE process = GetCurrentProcess();
367   DWORD needed;
368 
369   if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
370     return false;
371 
372   for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
373     PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
374     PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
375     PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
376     PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
377     bool found_obj = false;
378     bool found_hdr = false;
379 
380     info.dso_base = (uintptr_t)mods[i];
381     for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
382       uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
383       uintptr_t end = begin + pish->Misc.VirtualSize;
384       if (!strncmp((const char *)pish->Name, ".text",
385                    IMAGE_SIZEOF_SHORT_NAME)) {
386         if (targetAddr >= begin && targetAddr < end)
387           found_obj = true;
388       } else if (!strncmp((const char *)pish->Name, ".eh_frame",
389                           IMAGE_SIZEOF_SHORT_NAME)) {
390         // FIXME: This section name actually is truncated, ideally we
391         // should locate and check the full long name instead.
392         info.dwarf_section = begin;
393         info.dwarf_section_length = pish->Misc.VirtualSize;
394         found_hdr = true;
395       }
396       if (found_obj && found_hdr)
397         return true;
398     }
399   }
400   return false;
401 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
402   struct dl_iterate_cb_data {
403     LocalAddressSpace *addressSpace;
404     UnwindInfoSections *sects;
405     uintptr_t targetAddr;
406   };
407 
408   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
409   int found = dl_iterate_phdr(
410       [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
411         auto cbdata = static_cast<dl_iterate_cb_data *>(data);
412         bool found_obj = false;
413         bool found_hdr = false;
414 
415         assert(cbdata);
416         assert(cbdata->sects);
417 
418         if (cbdata->targetAddr < pinfo->dlpi_addr) {
419           return false;
420         }
421 
422 #if !defined(Elf_Half)
423         typedef ElfW(Half) Elf_Half;
424 #endif
425 #if !defined(Elf_Phdr)
426         typedef ElfW(Phdr) Elf_Phdr;
427 #endif
428 #if !defined(Elf_Addr) && defined(__ANDROID__)
429         typedef ElfW(Addr) Elf_Addr;
430 #endif
431 
432  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
433   #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
434    #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
435   #endif
436         size_t object_length;
437 #if defined(__ANDROID__)
438         Elf_Addr image_base =
439             pinfo->dlpi_phnum
440                 ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
441                       reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
442                           ->p_offset
443                 : 0;
444 #endif
445 
446         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
447           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
448           if (phdr->p_type == PT_LOAD) {
449             uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
450 #if defined(__ANDROID__)
451             if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
452               begin = begin + image_base;
453 #endif
454             uintptr_t end = begin + phdr->p_memsz;
455             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
456               cbdata->sects->dso_base = begin;
457               object_length = phdr->p_memsz;
458               found_obj = true;
459             }
460           } else if (phdr->p_type == PT_GNU_EH_FRAME) {
461             EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
462             uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
463 #if defined(__ANDROID__)
464             if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
465               eh_frame_hdr_start = eh_frame_hdr_start + image_base;
466 #endif
467             cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
468             cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
469             EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
470                 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
471                 hdrInfo);
472             cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
473             found_hdr = true;
474           }
475         }
476 
477         if (found_obj && found_hdr) {
478           cbdata->sects->dwarf_section_length = object_length;
479           return true;
480         } else {
481           return false;
482         }
483  #else // defined(_LIBUNWIND_ARM_EHABI)
484         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
485           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
486           if (phdr->p_type == PT_LOAD) {
487             uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
488             uintptr_t end = begin + phdr->p_memsz;
489             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
490               found_obj = true;
491           } else if (phdr->p_type == PT_ARM_EXIDX) {
492             uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
493             cbdata->sects->arm_section = exidx_start;
494             cbdata->sects->arm_section_length = phdr->p_memsz;
495             found_hdr = true;
496           }
497         }
498         return found_obj && found_hdr;
499  #endif
500       },
501       &cb_data);
502   return static_cast<bool>(found);
503 #endif
504 
505   return false;
506 }
507 
508 
509 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
510 #ifdef __APPLE__
511   return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
512 #else
513   // TO DO: if OS has way to dynamically register FDEs, check that.
514   (void)targetAddr;
515   (void)fde;
516   return false;
517 #endif
518 }
519 
520 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
521                                                 size_t bufLen,
522                                                 unw_word_t *offset) {
523 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
524   Dl_info dyldInfo;
525   if (dladdr((void *)addr, &dyldInfo)) {
526     if (dyldInfo.dli_sname != NULL) {
527       snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
528       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
529       return true;
530     }
531   }
532 #endif
533   return false;
534 }
535 
536 
537 
538 #ifdef UNW_REMOTE
539 
540 /// RemoteAddressSpace is used as a template parameter to UnwindCursor when
541 /// unwinding a thread in the another process.  The other process can be a
542 /// different endianness and a different pointer size which is handled by
543 /// the P template parameter.
544 template <typename P>
545 class RemoteAddressSpace {
546 public:
547   RemoteAddressSpace(task_t task) : fTask(task) {}
548 
549   typedef typename P::uint_t pint_t;
550 
551   uint8_t   get8(pint_t addr);
552   uint16_t  get16(pint_t addr);
553   uint32_t  get32(pint_t addr);
554   uint64_t  get64(pint_t addr);
555   pint_t    getP(pint_t addr);
556   uint64_t  getULEB128(pint_t &addr, pint_t end);
557   int64_t   getSLEB128(pint_t &addr, pint_t end);
558   pint_t    getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
559                         pint_t datarelBase = 0);
560   bool      findFunctionName(pint_t addr, char *buf, size_t bufLen,
561                         unw_word_t *offset);
562   bool      findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
563   bool      findOtherFDE(pint_t targetAddr, pint_t &fde);
564 private:
565   void *localCopy(pint_t addr);
566 
567   task_t fTask;
568 };
569 
570 template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) {
571   return *((uint8_t *)localCopy(addr));
572 }
573 
574 template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) {
575   return P::E::get16(*(uint16_t *)localCopy(addr));
576 }
577 
578 template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) {
579   return P::E::get32(*(uint32_t *)localCopy(addr));
580 }
581 
582 template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) {
583   return P::E::get64(*(uint64_t *)localCopy(addr));
584 }
585 
586 template <typename P>
587 typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) {
588   return P::getP(*(uint64_t *)localCopy(addr));
589 }
590 
591 template <typename P>
592 uint64_t RemoteAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
593   uintptr_t size = (end - addr);
594   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
595   LocalAddressSpace::pint_t sladdr = laddr;
596   uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
597   addr += (laddr - sladdr);
598   return result;
599 }
600 
601 template <typename P>
602 int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
603   uintptr_t size = (end - addr);
604   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
605   LocalAddressSpace::pint_t sladdr = laddr;
606   uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
607   addr += (laddr - sladdr);
608   return result;
609 }
610 
611 template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
612   // FIX ME
613 }
614 
615 template <typename P>
616 bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
617                                              size_t bufLen,
618                                              unw_word_t *offset) {
619   // FIX ME
620 }
621 
622 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
623 /// libunwind.h points to.
624 struct unw_addr_space {
625   cpu_type_t cpuType;
626   task_t taskPort;
627 };
628 
629 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
630 /// to when examining
631 /// a 32-bit intel process.
632 struct unw_addr_space_i386 : public unw_addr_space {
633   unw_addr_space_i386(task_t task) : oas(task) {}
634   RemoteAddressSpace<Pointer32<LittleEndian>> oas;
635 };
636 
637 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
638 /// points to when examining
639 /// a 64-bit intel process.
640 struct unw_addr_space_x86_64 : public unw_addr_space {
641   unw_addr_space_x86_64(task_t task) : oas(task) {}
642   RemoteAddressSpace<Pointer64<LittleEndian>> oas;
643 };
644 
645 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
646 /// to when examining
647 /// a 32-bit PowerPC process.
648 struct unw_addr_space_ppc : public unw_addr_space {
649   unw_addr_space_ppc(task_t task) : oas(task) {}
650   RemoteAddressSpace<Pointer32<BigEndian>> oas;
651 };
652 
653 #endif // UNW_REMOTE
654 
655 } // namespace libunwind
656 
657 #endif // __ADDRESSSPACE_HPP__
658