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