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