1 //===------------------------- AddressSpace.hpp ---------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
9 // Abstracts accessing local vs remote address spaces.
11 //===----------------------------------------------------------------------===//
13 #ifndef __ADDRESSSPACE_HPP__
14 #define __ADDRESSSPACE_HPP__
21 #if !_LIBUNWIND_IS_BAREMETAL
26 #include <mach-o/getsect.h>
28 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
32 #include "libunwind.h"
35 #include "Registers.hpp"
37 #if LIBCXXABI_ARM_EHABI
40 typedef long unsigned int *_Unwind_Ptr;
41 extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len);
43 // Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system.
44 #define dl_unwind_find_exidx __gnu_Unwind_Find_exidx
46 #elif !_LIBUNWIND_IS_BAREMETAL
48 #else // _LIBUNWIND_IS_BAREMETAL
49 // When statically linked on bare-metal, the symbols for the EH table are looked
50 // up without going through the dynamic loader.
52 uint32_t functionOffset;
53 uint32_t unwindOpcodes;
55 extern EHTEntry __exidx_start;
56 extern EHTEntry __exidx_end;
57 #endif // !_LIBUNWIND_IS_BAREMETAL
59 #endif // LIBCXXABI_ARM_EHABI
63 /// Used by findUnwindSections() to return info about needed sections.
64 struct UnwindInfoSections {
65 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \
66 _LIBUNWIND_SUPPORT_COMPACT_UNWIND
67 // No dso_base for ARM EHABI.
70 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
71 uintptr_t dwarf_section;
72 uintptr_t dwarf_section_length;
74 #if _LIBUNWIND_SUPPORT_DWARF_INDEX
75 uintptr_t dwarf_index_section;
76 uintptr_t dwarf_index_section_length;
78 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
79 uintptr_t compact_unwind_section;
80 uintptr_t compact_unwind_section_length;
82 #if LIBCXXABI_ARM_EHABI
83 uintptr_t arm_section;
84 uintptr_t arm_section_length;
89 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
90 /// unwinding a thread in the same process. The wrappers compile away,
91 /// making local unwinds fast.
92 class __attribute__((visibility("hidden"))) LocalAddressSpace {
95 typedef uint64_t pint_t;
96 typedef int64_t sint_t;
98 typedef uint32_t pint_t;
99 typedef int32_t sint_t;
101 uint8_t get8(pint_t addr) {
103 memcpy(&val, (void *)addr, sizeof(val));
106 uint16_t get16(pint_t addr) {
108 memcpy(&val, (void *)addr, sizeof(val));
111 uint32_t get32(pint_t addr) {
113 memcpy(&val, (void *)addr, sizeof(val));
116 uint64_t get64(pint_t addr) {
118 memcpy(&val, (void *)addr, sizeof(val));
121 double getDouble(pint_t addr) {
123 memcpy(&val, (void *)addr, sizeof(val));
126 v128 getVector(pint_t addr) {
128 memcpy(&val, (void *)addr, sizeof(val));
131 uintptr_t getP(pint_t addr);
132 static uint64_t getULEB128(pint_t &addr, pint_t end);
133 static int64_t getSLEB128(pint_t &addr, pint_t end);
135 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
136 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
138 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
139 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
141 static LocalAddressSpace sThisAddressSpace;
144 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
152 /// Read a ULEB128 into a 64-bit word.
153 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
154 const uint8_t *p = (uint8_t *)addr;
155 const uint8_t *pend = (uint8_t *)end;
162 _LIBUNWIND_ABORT("truncated uleb128 expression");
166 if (bit >= 64 || b << bit >> bit != b) {
167 _LIBUNWIND_ABORT("malformed uleb128 expression");
172 } while (*p++ >= 0x80);
177 /// Read a SLEB128 into a 64-bit word.
178 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
179 const uint8_t *p = (uint8_t *)addr;
180 const uint8_t *pend = (uint8_t *)end;
186 _LIBUNWIND_ABORT("truncated sleb128 expression");
188 result |= ((byte & 0x7f) << bit);
190 } while (byte & 0x80);
191 // sign extend negative numbers
192 if ((byte & 0x40) != 0)
193 result |= (-1LL) << bit;
198 inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr,
201 pint_t startAddr = addr;
202 const uint8_t *p = (uint8_t *)addr;
206 switch (encoding & 0x0F) {
212 case DW_EH_PE_uleb128:
213 result = (pint_t)getULEB128(addr, end);
215 case DW_EH_PE_udata2:
216 result = get16(addr);
220 case DW_EH_PE_udata4:
221 result = get32(addr);
225 case DW_EH_PE_udata8:
226 result = (pint_t)get64(addr);
230 case DW_EH_PE_sleb128:
231 result = (pint_t)getSLEB128(addr, end);
233 case DW_EH_PE_sdata2:
234 // Sign extend from signed 16-bit value.
235 result = (pint_t)(int16_t)get16(addr);
239 case DW_EH_PE_sdata4:
240 // Sign extend from signed 32-bit value.
241 result = (pint_t)(int32_t)get32(addr);
245 case DW_EH_PE_sdata8:
246 result = (pint_t)get64(addr);
251 _LIBUNWIND_ABORT("unknown pointer encoding");
254 // then add relative offset
255 switch (encoding & 0x70) {
256 case DW_EH_PE_absptr:
262 case DW_EH_PE_textrel:
263 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
265 case DW_EH_PE_datarel:
266 _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported");
268 case DW_EH_PE_funcrel:
269 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
271 case DW_EH_PE_aligned:
272 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
275 _LIBUNWIND_ABORT("unknown pointer encoding");
279 if (encoding & DW_EH_PE_indirect)
280 result = getP(result);
286 struct dyld_unwind_sections
288 const struct mach_header* mh;
289 const void* dwarf_section;
290 uintptr_t dwarf_section_length;
291 const void* compact_unwind_section;
292 uintptr_t compact_unwind_section_length;
294 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
295 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
296 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
297 // In 10.7.0 or later, libSystem.dylib implements this function.
298 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
300 // In 10.6.x and earlier, we need to implement this functionality.
301 static inline bool _dyld_find_unwind_sections(void* addr,
302 dyld_unwind_sections* info) {
303 // Find mach-o image containing address.
305 if (!dladdr(addr, &dlinfo))
307 const mach_header *mh = (const mach_header *)dlinfo.dli_saddr;
309 // Find dwarf unwind section in that image.
311 const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size);
315 // Fill in return struct.
317 info->dwarf_section = p;
318 info->dwarf_section_length = size;
319 info->compact_unwind_section = 0;
320 info->compact_unwind_section_length = 0;
327 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
328 UnwindInfoSections &info) {
330 dyld_unwind_sections dyldInfo;
331 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
332 info.dso_base = (uintptr_t)dyldInfo.mh;
333 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
334 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
335 info.dwarf_section_length = dyldInfo.dwarf_section_length;
337 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
338 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
341 #elif LIBCXXABI_ARM_EHABI
342 #if _LIBUNWIND_IS_BAREMETAL
343 // Bare metal is statically linked, so no need to ask the dynamic loader
344 info.arm_section = (uintptr_t)(&__exidx_start);
345 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
348 info.arm_section = (uintptr_t) dl_unwind_find_exidx(
349 (_Unwind_Ptr) targetAddr, &length);
350 info.arm_section_length = (uintptr_t)length;
352 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n",
353 info.arm_section, info.arm_section_length);
354 if (info.arm_section && info.arm_section_length)
362 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
364 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
366 // TO DO: if OS has way to dynamically register FDEs, check that.
373 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
375 unw_word_t *offset) {
376 #if !_LIBUNWIND_IS_BAREMETAL
378 if (dladdr((void *)addr, &dyldInfo)) {
379 if (dyldInfo.dli_sname != NULL) {
380 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
381 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
393 /// OtherAddressSpace is used as a template parameter to UnwindCursor when
394 /// unwinding a thread in the another process. The other process can be a
395 /// different endianness and a different pointer size which is handled by
396 /// the P template parameter.
397 template <typename P>
398 class OtherAddressSpace {
400 OtherAddressSpace(task_t task) : fTask(task) {}
402 typedef typename P::uint_t pint_t;
404 uint8_t get8(pint_t addr);
405 uint16_t get16(pint_t addr);
406 uint32_t get32(pint_t addr);
407 uint64_t get64(pint_t addr);
408 pint_t getP(pint_t addr);
409 uint64_t getULEB128(pint_t &addr, pint_t end);
410 int64_t getSLEB128(pint_t &addr, pint_t end);
411 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
412 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
414 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
415 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
417 void *localCopy(pint_t addr);
422 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
423 return *((uint8_t *)localCopy(addr));
426 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
427 return P::E::get16(*(uint16_t *)localCopy(addr));
430 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
431 return P::E::get32(*(uint32_t *)localCopy(addr));
434 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
435 return P::E::get64(*(uint64_t *)localCopy(addr));
438 template <typename P>
439 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
440 return P::getP(*(uint64_t *)localCopy(addr));
443 template <typename P>
444 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
445 uintptr_t size = (end - addr);
446 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
447 LocalAddressSpace::pint_t sladdr = laddr;
448 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
449 addr += (laddr - sladdr);
453 template <typename P>
454 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
455 uintptr_t size = (end - addr);
456 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
457 LocalAddressSpace::pint_t sladdr = laddr;
458 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
459 addr += (laddr - sladdr);
463 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
467 template <typename P>
468 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
469 size_t bufLen, unw_word_t *offset) {
473 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
474 /// libunwind.h points to.
475 struct unw_addr_space {
480 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
481 /// to when examining
482 /// a 32-bit intel process.
483 struct unw_addr_space_i386 : public unw_addr_space {
484 unw_addr_space_i386(task_t task) : oas(task) {}
485 OtherAddressSpace<Pointer32<LittleEndian> > oas;
488 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
489 /// points to when examining
490 /// a 64-bit intel process.
491 struct unw_addr_space_x86_64 : public unw_addr_space {
492 unw_addr_space_x86_64(task_t task) : oas(task) {}
493 OtherAddressSpace<Pointer64<LittleEndian> > oas;
496 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
497 /// to when examining
498 /// a 32-bit PowerPC process.
499 struct unw_addr_space_ppc : public unw_addr_space {
500 unw_addr_space_ppc(task_t task) : oas(task) {}
501 OtherAddressSpace<Pointer32<BigEndian> > oas;
506 } // namespace libunwind
508 #endif // __ADDRESSSPACE_HPP__