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__
22 #include <mach-o/getsect.h>
24 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
28 #include "libunwind.h"
31 #include "Registers.hpp"
35 /// Used by findUnwindSections() to return info about needed sections.
36 struct UnwindInfoSections {
38 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
39 uintptr_t dwarf_section;
40 uintptr_t dwarf_section_length;
42 #if _LIBUNWIND_SUPPORT_DWARF_INDEX
43 uintptr_t dwarf_index_section;
44 uintptr_t dwarf_index_section_length;
46 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
47 uintptr_t compact_unwind_section;
48 uintptr_t compact_unwind_section_length;
53 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
54 /// unwinding a thread in the same process. The wrappers compile away,
55 /// making local unwinds fast.
56 class __attribute__((visibility("hidden"))) LocalAddressSpace {
59 typedef uint64_t pint_t;
60 typedef int64_t sint_t;
62 typedef uint32_t pint_t;
63 typedef int32_t sint_t;
65 uint8_t get8(pint_t addr) { return *((uint8_t *)addr); }
66 uint16_t get16(pint_t addr) { return *((uint16_t *)addr); }
67 uint32_t get32(pint_t addr) { return *((uint32_t *)addr); }
68 uint64_t get64(pint_t addr) { return *((uint64_t *)addr); }
69 double getDouble(pint_t addr) { return *((double *)addr); }
70 v128 getVector(pint_t addr) { return *((v128 *)addr); }
71 uintptr_t getP(pint_t addr);
72 static uint64_t getULEB128(pint_t &addr, pint_t end);
73 static int64_t getSLEB128(pint_t &addr, pint_t end);
75 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
76 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
78 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
79 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
81 static LocalAddressSpace sThisAddressSpace;
85 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
93 /// Read a ULEB128 into a 64-bit word.
94 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
95 const uint8_t *p = (uint8_t *)addr;
96 const uint8_t *pend = (uint8_t *)end;
103 _LIBUNWIND_ABORT("truncated uleb128 expression");
107 if (bit >= 64 || b << bit >> bit != b) {
108 _LIBUNWIND_ABORT("malformed uleb128 expression");
113 } while (*p++ >= 0x80);
118 /// Read a SLEB128 into a 64-bit word.
119 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
120 const uint8_t *p = (uint8_t *)addr;
121 const uint8_t *pend = (uint8_t *)end;
127 _LIBUNWIND_ABORT("truncated sleb128 expression");
129 result |= ((byte & 0x7f) << bit);
131 } while (byte & 0x80);
132 // sign extend negative numbers
133 if ((byte & 0x40) != 0)
134 result |= (-1LL) << bit;
139 inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr,
142 pint_t startAddr = addr;
143 const uint8_t *p = (uint8_t *)addr;
147 switch (encoding & 0x0F) {
153 case DW_EH_PE_uleb128:
154 result = (pint_t)getULEB128(addr, end);
156 case DW_EH_PE_udata2:
157 result = get16(addr);
161 case DW_EH_PE_udata4:
162 result = get32(addr);
166 case DW_EH_PE_udata8:
167 result = (pint_t)get64(addr);
171 case DW_EH_PE_sleb128:
172 result = (pint_t)getSLEB128(addr, end);
174 case DW_EH_PE_sdata2:
175 result = (uint16_t)get16(addr);
179 case DW_EH_PE_sdata4:
180 result = (uint32_t)get32(addr);
184 case DW_EH_PE_sdata8:
185 result = (pint_t)get64(addr);
190 _LIBUNWIND_ABORT("unknown pointer encoding");
193 // then add relative offset
194 switch (encoding & 0x70) {
195 case DW_EH_PE_absptr:
201 case DW_EH_PE_textrel:
202 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
204 case DW_EH_PE_datarel:
205 _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported");
207 case DW_EH_PE_funcrel:
208 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
210 case DW_EH_PE_aligned:
211 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
214 _LIBUNWIND_ABORT("unknown pointer encoding");
218 if (encoding & DW_EH_PE_indirect)
219 result = getP(result);
225 struct dyld_unwind_sections
227 const struct mach_header* mh;
228 const void* dwarf_section;
229 uintptr_t dwarf_section_length;
230 const void* compact_unwind_section;
231 uintptr_t compact_unwind_section_length;
233 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
234 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
235 // In 10.7.0 or later, libSystem.dylib implements this function.
236 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
238 // In 10.6.x and earlier, we need to implement this functionality.
239 static inline bool _dyld_find_unwind_sections(void* addr,
240 dyld_unwind_sections* info) {
241 // Find mach-o image containing address.
243 if (!dladdr(addr, &dlinfo))
245 const mach_header *mh = (const mach_header *)dlinfo.dli_saddr;
247 // Find dwarf unwind section in that image.
249 const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size);
253 // Fill in return struct.
255 info->dwarf_section = p;
256 info->dwarf_section_length = size;
257 info->compact_unwind_section = 0;
258 info->compact_unwind_section_length = 0;
265 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
266 UnwindInfoSections &info) {
268 dyld_unwind_sections dyldInfo;
269 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
270 info.dso_base = (uintptr_t)dyldInfo.mh;
271 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
272 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
273 info.dwarf_section_length = dyldInfo.dwarf_section_length;
275 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
276 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
288 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
290 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
292 // TO DO: if OS has way to dynamically register FDEs, check that.
297 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
299 unw_word_t *offset) {
301 if (dladdr((void *)addr, &dyldInfo)) {
302 if (dyldInfo.dli_sname != NULL) {
303 strlcpy(buf, dyldInfo.dli_sname, bufLen);
304 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
315 /// OtherAddressSpace is used as a template parameter to UnwindCursor when
316 /// unwinding a thread in the another process. The other process can be a
317 /// different endianness and a different pointer size which is handled by
318 /// the P template parameter.
319 template <typename P>
320 class OtherAddressSpace {
322 OtherAddressSpace(task_t task) : fTask(task) {}
324 typedef typename P::uint_t pint_t;
326 uint8_t get8(pint_t addr);
327 uint16_t get16(pint_t addr);
328 uint32_t get32(pint_t addr);
329 uint64_t get64(pint_t addr);
330 pint_t getP(pint_t addr);
331 uint64_t getULEB128(pint_t &addr, pint_t end);
332 int64_t getSLEB128(pint_t &addr, pint_t end);
333 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
334 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
336 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
337 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
339 void *localCopy(pint_t addr);
344 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
345 return *((uint8_t *)localCopy(addr));
348 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
349 return P::E::get16(*(uint16_t *)localCopy(addr));
352 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
353 return P::E::get32(*(uint32_t *)localCopy(addr));
356 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
357 return P::E::get64(*(uint64_t *)localCopy(addr));
360 template <typename P>
361 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
362 return P::getP(*(uint64_t *)localCopy(addr));
365 template <typename P>
366 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
367 uintptr_t size = (end - addr);
368 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
369 LocalAddressSpace::pint_t sladdr = laddr;
370 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
371 addr += (laddr - sladdr);
375 template <typename P>
376 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
377 uintptr_t size = (end - addr);
378 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
379 LocalAddressSpace::pint_t sladdr = laddr;
380 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
381 addr += (laddr - sladdr);
385 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
389 template <typename P>
390 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
391 size_t bufLen, unw_word_t *offset) {
395 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
396 /// libunwind.h points to.
397 struct unw_addr_space {
402 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
403 /// to when examining
404 /// a 32-bit intel process.
405 struct unw_addr_space_i386 : public unw_addr_space {
406 unw_addr_space_i386(task_t task) : oas(task) {}
407 OtherAddressSpace<Pointer32<LittleEndian> > oas;
410 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
411 /// points to when examining
412 /// a 64-bit intel process.
413 struct unw_addr_space_x86_64 : public unw_addr_space {
414 unw_addr_space_x86_64(task_t task) : oas(task) {}
415 OtherAddressSpace<Pointer64<LittleEndian> > oas;
418 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
419 /// to when examining
420 /// a 32-bit PowerPC process.
421 struct unw_addr_space_ppc : public unw_addr_space {
422 unw_addr_space_ppc(task_t task) : oas(task) {}
423 OtherAddressSpace<Pointer32<BigEndian> > oas;
428 } // namespace libunwind
430 #endif // __ADDRESSSPACE_HPP__