//===------------------------- AddressSpace.hpp ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//
// Abstracts accessing local vs remote address spaces.
//
//===----------------------------------------------------------------------===//
static int rangeCmp(void *, const void *, const void *);
static int rangeCmpKey(void *, const void *, const void *);
static int dsoTableCmp(void *, const void *, const void *);
static int dsoTableCmpKey(void *, const void *, const void *);
static int phdr_callback(struct dl_phdr_info *, size_t, void *);
struct unw_proc_info_t {
uintptr_t data_base; // Base address for data-relative relocations
uintptr_t start_ip; // Start address of function
uintptr_t end_ip; // First address after end of function
uintptr_t lsda; // Address of Language Specific Data Area
uintptr_t handler; // Personality routine
uintptr_t extra_args; // Extra stack space for frameless routines
uintptr_t unwind_info; // Address of DWARF unwind info
};
/// LocalAddressSpace is used as a template parameter to UnwindCursor when
/// unwinding a thread in the same process. The wrappers compile away,
/// making local unwinds fast.
class LocalAddressSpace {
public:
typedef uintptr_t pint_t;
typedef intptr_t sint_t;
// first get value
switch (encoding & 0x0F) {
case DW_EH_PE_ptr:
result = getP(addr);
p += sizeof(pint_t);
addr = (pint_t)p;
break;
case DW_EH_PE_uleb128:
result = getULEB128(addr, end);
break;
case DW_EH_PE_udata2:
result = get16(addr);
p += 2;
addr = (pint_t)p;
break;
case DW_EH_PE_udata4:
result = get32(addr);
p += 4;
addr = (pint_t)p;
break;
case DW_EH_PE_udata8:
result = get64(addr);
p += 8;
addr = (pint_t)p;
break;
case DW_EH_PE_sleb128:
result = getSLEB128(addr, end);
break;
case DW_EH_PE_sdata2:
result = (int16_t)get16(addr);
p += 2;
addr = (pint_t)p;
break;
case DW_EH_PE_sdata4:
result = (int32_t)get32(addr);
p += 4;
addr = (pint_t)p;
break;
case DW_EH_PE_sdata8:
result = get64(addr);
p += 8;
addr = (pint_t)p;
break;
case DW_EH_PE_omit:
result = 0;
break;
default:
assert(0 && "unknown pointer encoding");
}
// then add relative offset
switch (encoding & 0x70) {
case DW_EH_PE_absptr:
// do nothing
break;
case DW_EH_PE_pcrel:
result += startAddr;
break;
case DW_EH_PE_textrel:
assert(0 && "DW_EH_PE_textrel pointer encoding not supported");
break;
case DW_EH_PE_datarel:
assert(ctx != NULL && "DW_EH_PE_datarel without context");
if (ctx)
result += ctx->data_base;
break;
case DW_EH_PE_funcrel:
assert(ctx != NULL && "DW_EH_PE_funcrel without context");
if (ctx)
result += ctx->start_ip;
break;
case DW_EH_PE_aligned:
__builtin_unreachable();
default:
assert(0 && "unknown pointer encoding");
break;
}
if (encoding & DW_EH_PE_indirect)
result = getP(result);
return result;
}
bool findFDE(pint_t pc, pint_t &fdeStart, pint_t &data_base) {
Range *n;
for (;;) {
pthread_rwlock_rdlock(&fdeTreeLock);
n = (Range *)rb_tree_find_node(&segmentTree, &pc);
pthread_rwlock_unlock(&fdeTreeLock);
if (n != NULL)
break;
if (!needsReload)
break;
lazyReload();
}
if (n == NULL)
return false;
if (n->hdr_start == 0) {
fdeStart = n->hdr_base;
data_base = n->data_base;
return true;
}
pint_t base = n->hdr_base;
pint_t first = n->hdr_start;
for (pint_t len = n->hdr_entries; len > 1; ) {
pint_t next = first + (len / 2) * 8;
pint_t nextPC = base + (int32_t)get32(next);
if (nextPC == pc) {
first = next;
break;
}
if (nextPC < pc) {
first = next;
len -= (len / 2);
} else {
len /= 2;
}
}
fdeStart = base + (int32_t)get32(first + 4);
data_base = n->data_base;
return true;
}