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__