Importing sys/libunwind for clang
Change-Id: Ib073b27e3b883837e682414ef7df56c84ca10816
This commit is contained in:
parent
fed2e50bd7
commit
472758f313
|
@ -1780,6 +1780,7 @@
|
|||
./usr/include/ulimit.h minix-sys
|
||||
./usr/include/unctrl.h minix-sys
|
||||
./usr/include/unistd.h minix-sys
|
||||
./usr/include/unwind.h minix-sys llvm
|
||||
./usr/include/util.h minix-sys
|
||||
./usr/include/utime.h minix-sys
|
||||
./usr/include/utmp.h minix-sys
|
||||
|
|
480
sys/lib/libunwind/AddressSpace.hpp
Normal file
480
sys/lib/libunwind/AddressSpace.hpp
Normal file
|
@ -0,0 +1,480 @@
|
|||
//===------------------------- 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __ADDRESSSPACE_HPP__
|
||||
#define __ADDRESSSPACE_HPP__
|
||||
|
||||
#include <sys/rbtree.h>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#if !defined(__minix)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#define pthread_rwlock_init(l, d) /* nothing */
|
||||
#define pthread_rwlock_rdlock(l) /* nothing */
|
||||
#define pthread_rwlock_wrlock(l) /* nothing */
|
||||
#define pthread_rwlock_unlock(l) /* nothing */
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
#include "dwarf2.h"
|
||||
|
||||
namespace _Unwind {
|
||||
|
||||
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
|
||||
uint32_t unwind_info_size; // Size of DWARF unwind info
|
||||
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;
|
||||
|
||||
typedef void (*findPCRange_t)(LocalAddressSpace &, pint_t, pint_t &pcStart,
|
||||
pint_t &pcEnd);
|
||||
|
||||
LocalAddressSpace(findPCRange_t findPCRange_)
|
||||
: findPCRange(findPCRange_), needsReload(true) {
|
||||
static const rb_tree_ops_t segmentTreeOps = {
|
||||
rangeCmp, rangeCmpKey, offsetof(Range, range_link), NULL
|
||||
};
|
||||
static const rb_tree_ops_t dsoTreeOps = {
|
||||
dsoTableCmp, dsoTableCmpKey, offsetof(Range, dso_link), NULL
|
||||
};
|
||||
rb_tree_init(&segmentTree, &segmentTreeOps);
|
||||
rb_tree_init(&dsoTree, &dsoTreeOps);
|
||||
pthread_rwlock_init(&fdeTreeLock, NULL);
|
||||
}
|
||||
|
||||
uint8_t get8(pint_t addr) { return *((uint8_t *)addr); }
|
||||
|
||||
uint16_t get16(pint_t addr) { return *((uint16_t *)addr); }
|
||||
|
||||
uint32_t get32(pint_t addr) { return *((uint32_t *)addr); }
|
||||
|
||||
uint64_t get64(pint_t addr) { return *((uint64_t *)addr); }
|
||||
|
||||
uintptr_t getP(pint_t addr) {
|
||||
if (sizeof(uintptr_t) == sizeof(uint32_t))
|
||||
return get32(addr);
|
||||
else
|
||||
return get64(addr);
|
||||
}
|
||||
|
||||
uint64_t getULEB128(pint_t &addr, pint_t end) {
|
||||
uint64_t result = 0;
|
||||
uint8_t byte;
|
||||
int bit = 0;
|
||||
do {
|
||||
uint64_t b;
|
||||
|
||||
assert(addr != end);
|
||||
|
||||
byte = get8(addr++);
|
||||
b = byte & 0x7f;
|
||||
|
||||
assert(bit < 64);
|
||||
assert(b << bit >> bit == b);
|
||||
|
||||
result |= b << bit;
|
||||
bit += 7;
|
||||
} while (byte >= 0x80);
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t getSLEB128(pint_t &addr, pint_t end) {
|
||||
uint64_t result = 0;
|
||||
uint8_t byte;
|
||||
int bit = 0;
|
||||
do {
|
||||
uint64_t b;
|
||||
|
||||
assert(addr != end);
|
||||
|
||||
byte = get8(addr++);
|
||||
b = byte & 0x7f;
|
||||
|
||||
assert(bit < 64);
|
||||
assert(b << bit >> bit == b);
|
||||
|
||||
result |= b << bit;
|
||||
bit += 7;
|
||||
} while (byte >= 0x80);
|
||||
// sign extend negative numbers
|
||||
if ((byte & 0x40) != 0)
|
||||
result |= (-1LL) << bit;
|
||||
return result;
|
||||
}
|
||||
|
||||
pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
||||
const unw_proc_info_t *ctx) {
|
||||
pint_t startAddr = addr;
|
||||
const uint8_t *p = (uint8_t *)addr;
|
||||
pint_t result;
|
||||
|
||||
if (encoding == DW_EH_PE_omit)
|
||||
return 0;
|
||||
if (encoding == DW_EH_PE_aligned) {
|
||||
addr = (addr + sizeof(pint_t) - 1) & sizeof(pint_t);
|
||||
return getP(addr);
|
||||
}
|
||||
|
||||
// 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;
|
||||
return true;
|
||||
}
|
||||
|
||||
pint_t base = n->hdr_base;
|
||||
pint_t first = n->hdr_start;
|
||||
pint_t len = n->hdr_entries;
|
||||
while (len) {
|
||||
pint_t next = first + ((len + 1) / 2) * 8;
|
||||
pint_t nextPC = base + (int32_t)get32(next);
|
||||
if (nextPC == pc) {
|
||||
first = next;
|
||||
break;
|
||||
}
|
||||
if (nextPC < pc) {
|
||||
len -= (len + 1) / 2;
|
||||
first = next;
|
||||
} else if (len == 1)
|
||||
break;
|
||||
else
|
||||
len = (len + 1) / 2;
|
||||
}
|
||||
fdeStart = base + (int32_t)get32(first + 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addFDE(pint_t pcStart, pint_t pcEnd, pint_t fde) {
|
||||
pthread_rwlock_wrlock(&fdeTreeLock);
|
||||
Range *n = (Range *)malloc(sizeof(*n));
|
||||
n->hdr_base = fde;
|
||||
n->hdr_start = 0;
|
||||
n->hdr_entries = 0;
|
||||
n->first_pc = pcStart;
|
||||
n->last_pc = pcEnd;
|
||||
n->data_base = 0;
|
||||
n->ehframe_base = 0;
|
||||
if (rb_tree_insert_node(&segmentTree, n) == n) {
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
return true;
|
||||
}
|
||||
free(n);
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool removeFDE(pint_t pcStart, pint_t pcEnd, pint_t fde) {
|
||||
pthread_rwlock_wrlock(&fdeTreeLock);
|
||||
Range *n = (Range *)rb_tree_find_node(&segmentTree, &pcStart);
|
||||
if (n == NULL) {
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
return false;
|
||||
}
|
||||
assert(n->first_pc == pcStart);
|
||||
assert(n->last_pc == pcEnd);
|
||||
assert(n->hdr_base == fde);
|
||||
assert(n->hdr_start == 0);
|
||||
assert(n->hdr_entries == 0);
|
||||
assert(n->data_base == 0);
|
||||
assert(n->ehframe_base == 0);
|
||||
rb_tree_remove_node(&segmentTree, n);
|
||||
free(n);
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeDSO(pint_t ehFrameBase) {
|
||||
pthread_rwlock_wrlock(&fdeTreeLock);
|
||||
Range *n;
|
||||
n = (Range *)rb_tree_find_node(&dsoTree, &ehFrameBase);
|
||||
if (n == NULL) {
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
return;
|
||||
}
|
||||
rb_tree_remove_node(&dsoTree, n);
|
||||
rb_tree_remove_node(&segmentTree, n);
|
||||
free(n);
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
}
|
||||
|
||||
void setLazyReload() {
|
||||
pthread_rwlock_wrlock(&fdeTreeLock);
|
||||
needsReload = true;
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
}
|
||||
|
||||
private:
|
||||
findPCRange_t findPCRange;
|
||||
bool needsReload;
|
||||
#if !defined(__minix)
|
||||
pthread_rwlock_t fdeTreeLock;
|
||||
#endif /* !defined(__minix) */
|
||||
rb_tree_t segmentTree;
|
||||
rb_tree_t dsoTree;
|
||||
|
||||
friend int phdr_callback(struct dl_phdr_info *, size_t, void *);
|
||||
friend int rangeCmp(void *, const void *, const void *);
|
||||
friend int rangeCmpKey(void *, const void *, const void *);
|
||||
friend int dsoTableCmp(void *, const void *, const void *);
|
||||
friend int dsoTableCmpKey(void *, const void *, const void *);
|
||||
|
||||
void updateRange();
|
||||
|
||||
struct Range {
|
||||
rb_node_t range_link;
|
||||
rb_node_t dso_link;
|
||||
pint_t hdr_base; // Pointer to FDE if hdr_start == 0
|
||||
pint_t hdr_start;
|
||||
pint_t hdr_entries;
|
||||
pint_t first_pc;
|
||||
pint_t last_pc;
|
||||
pint_t data_base;
|
||||
pint_t ehframe_base;
|
||||
};
|
||||
|
||||
void lazyReload() {
|
||||
pthread_rwlock_wrlock(&fdeTreeLock);
|
||||
dl_iterate_phdr(phdr_callback, this);
|
||||
needsReload = false;
|
||||
pthread_rwlock_unlock(&fdeTreeLock);
|
||||
}
|
||||
|
||||
void addDSO(pint_t header, pint_t data_base) {
|
||||
if (header == 0)
|
||||
return;
|
||||
if (get8(header) != 1)
|
||||
return;
|
||||
if (get8(header + 3) != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
|
||||
return;
|
||||
pint_t end = header + 4;
|
||||
pint_t ehframe_base = getEncodedP(end, 0, get8(header + 1), NULL);
|
||||
pint_t entries = getEncodedP(end, 0, get8(header + 2), NULL);
|
||||
pint_t start = (end + 3) & ~pint_t(3);
|
||||
if (entries == 0)
|
||||
return;
|
||||
Range *n = (Range *)malloc(sizeof(*n));
|
||||
n->hdr_base = header;
|
||||
n->hdr_start = start;
|
||||
n->hdr_entries = entries;
|
||||
n->first_pc = header + (int32_t)get32(n->hdr_start);
|
||||
pint_t tmp;
|
||||
(*findPCRange)(
|
||||
*this, header + (int32_t)get32(n->hdr_start + (entries - 1) * 8 + 4),
|
||||
tmp, n->last_pc);
|
||||
n->data_base = data_base;
|
||||
n->ehframe_base = ehframe_base;
|
||||
|
||||
if (rb_tree_insert_node(&segmentTree, n) != n) {
|
||||
free(n);
|
||||
return;
|
||||
}
|
||||
rb_tree_insert_node(&dsoTree, n);
|
||||
}
|
||||
};
|
||||
|
||||
static int phdr_callback(struct dl_phdr_info *info, size_t size, void *data_) {
|
||||
LocalAddressSpace *data = (LocalAddressSpace *)data_;
|
||||
size_t eh_frame = 0, data_base = 0;
|
||||
const Elf_Phdr *hdr = info->dlpi_phdr;
|
||||
const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum;
|
||||
const Elf_Dyn *dyn;
|
||||
|
||||
for (; hdr != last_hdr; ++hdr) {
|
||||
switch (hdr->p_type) {
|
||||
case PT_GNU_EH_FRAME:
|
||||
eh_frame = info->dlpi_addr + hdr->p_vaddr;
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
dyn = (const Elf_Dyn *)(info->dlpi_addr + hdr->p_vaddr);
|
||||
while (dyn->d_tag != DT_NULL) {
|
||||
if (dyn->d_tag == DT_PLTGOT) {
|
||||
data_base = info->dlpi_addr + dyn->d_un.d_ptr;
|
||||
break;
|
||||
}
|
||||
++dyn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eh_frame)
|
||||
data->addDSO(eh_frame, data_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rangeCmp(void *context, const void *n1_, const void *n2_) {
|
||||
LocalAddressSpace::Range *n1 = (LocalAddressSpace::Range *)n1_;
|
||||
LocalAddressSpace::Range *n2 = (LocalAddressSpace::Range *)n2_;
|
||||
|
||||
if (n1->first_pc < n2->first_pc)
|
||||
return -1;
|
||||
if (n1->first_pc > n2->first_pc)
|
||||
return 1;
|
||||
assert(n1->last_pc == n2->last_pc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rangeCmpKey(void *context, const void *n_, const void *pc_) {
|
||||
LocalAddressSpace::Range *n = (LocalAddressSpace::Range *)n_;
|
||||
LocalAddressSpace::pint_t *pc = (LocalAddressSpace::pint_t *)pc_;
|
||||
if (n->last_pc < *pc)
|
||||
return -1;
|
||||
if (n->first_pc > *pc)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsoTableCmp(void *context, const void *n1_, const void *n2_) {
|
||||
LocalAddressSpace::Range *n1 = (LocalAddressSpace::Range *)n1_;
|
||||
LocalAddressSpace::Range *n2 = (LocalAddressSpace::Range *)n2_;
|
||||
|
||||
if (n1->ehframe_base < n2->ehframe_base)
|
||||
return -1;
|
||||
if (n1->ehframe_base > n2->ehframe_base)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsoTableCmpKey(void *context, const void *n_, const void *ptr_) {
|
||||
LocalAddressSpace::Range *n = (LocalAddressSpace::Range *)n_;
|
||||
LocalAddressSpace::pint_t *ptr = (LocalAddressSpace::pint_t *)ptr_;
|
||||
if (n->ehframe_base < *ptr)
|
||||
return -1;
|
||||
if (n->ehframe_base > *ptr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace _Unwind
|
||||
|
||||
#endif // __ADDRESSSPACE_HPP__
|
42
sys/lib/libunwind/CREDITS.TXT
Normal file
42
sys/lib/libunwind/CREDITS.TXT
Normal file
|
@ -0,0 +1,42 @@
|
|||
This file is a partial list of people who have contributed to the LLVM/libc++abi
|
||||
project. If you have contributed a patch or made some other contribution to
|
||||
LLVM/libc++abi, please submit a patch to this file to add yourself, and it will be
|
||||
done!
|
||||
|
||||
The list is sorted by surname and formatted to allow easy grepping and
|
||||
beautification by scripts. The fields are: name (N), email (E), web-address
|
||||
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
|
||||
(S).
|
||||
|
||||
N: Marshall Clow
|
||||
E: mclow.lists@gmail.com
|
||||
E: marshall@idio.com
|
||||
D: Architect and primary coauthor of libc++abi
|
||||
|
||||
N: Matthew Dempsky
|
||||
E: matthew@dempsky.org
|
||||
D: Minor patches and bug fixes.
|
||||
|
||||
N: Nowar Gu
|
||||
E: wenhan.gu@gmail.com
|
||||
D: Minor patches and fixes
|
||||
|
||||
N: Howard Hinnant
|
||||
E: hhinnant@apple.com
|
||||
D: Architect and primary coauthor of libc++abi
|
||||
|
||||
N: Nick Kledzik
|
||||
E: kledzik@apple.com
|
||||
|
||||
N: Bruce Mitchener, Jr.
|
||||
E: bruce.mitchener@gmail.com
|
||||
D: Minor typo fixes
|
||||
|
||||
N: Andrew Morrow
|
||||
E: andrew.c.morrow@gmail.com
|
||||
D: Minor patches and fixes
|
||||
|
||||
N: Erik Olofsson
|
||||
E: erik.olofsson@hansoft.se
|
||||
E: erik@olofsson.info
|
||||
D: Minor patches and fixes
|
597
sys/lib/libunwind/DwarfInstructions.hpp
Normal file
597
sys/lib/libunwind/DwarfInstructions.hpp
Normal file
|
@ -0,0 +1,597 @@
|
|||
//===-------------------------- DwarfInstructions.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.
|
||||
//
|
||||
//
|
||||
// Processor specific interpretation of DWARF unwind info.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __DWARF_INSTRUCTIONS_HPP__
|
||||
#define __DWARF_INSTRUCTIONS_HPP__
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "dwarf2.h"
|
||||
#include "AddressSpace.hpp"
|
||||
#include "Registers.hpp"
|
||||
#include "DwarfParser.hpp"
|
||||
|
||||
namespace _Unwind {
|
||||
|
||||
enum step_result {
|
||||
UNW_STEP_SUCCESS,
|
||||
UNW_STEP_END,
|
||||
UNW_STEP_FAILED
|
||||
};
|
||||
|
||||
/// DwarfInstructions maps abtract dwarf unwind instructions to a particular
|
||||
/// architecture
|
||||
template <typename A, typename R> class DwarfInstructions {
|
||||
public:
|
||||
typedef typename A::pint_t pint_t;
|
||||
typedef typename A::sint_t sint_t;
|
||||
|
||||
static step_result stepWithDwarf(A &, pint_t, pint_t, R &, unw_proc_info_t *);
|
||||
|
||||
private:
|
||||
// Pseudo-register used for return addresses.
|
||||
enum {
|
||||
DW_X86_RET_ADDR = 8,
|
||||
DW_X86_64_RET_ADDR = 16,
|
||||
};
|
||||
|
||||
static pint_t evaluateExpression(pint_t, A &, const R &, pint_t);
|
||||
static pint_t
|
||||
getSavedRegister(A &, const R &, pint_t,
|
||||
const typename CFI_Parser<A, R>::RegisterLocation &);
|
||||
static pint_t
|
||||
computeRegisterLocation(A &, const R &, pint_t,
|
||||
const typename CFI_Parser<A, R>::RegisterLocation &);
|
||||
|
||||
static int lastRestoreReg(const R &) { return R::LAST_RESTORE_REG; }
|
||||
static bool isReturnAddressRegister(int regno, const R &) {
|
||||
return regno == R::IP_PSEUDO_REG;
|
||||
}
|
||||
|
||||
static pint_t getCFA(A &addressSpace,
|
||||
const typename CFI_Parser<A, R>::PrologInfo &prolog,
|
||||
const R ®isters) {
|
||||
if (prolog.cfaRegister != 0)
|
||||
return registers.getRegister(prolog.cfaRegister) +
|
||||
prolog.cfaRegisterOffset;
|
||||
if (prolog.cfaExpression != 0)
|
||||
return evaluateExpression(prolog.cfaExpression, addressSpace, registers,
|
||||
0);
|
||||
assert(0 && "getCFA(): unknown location");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A, typename R>
|
||||
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
|
||||
A &addressSpace, const R ®isters, pint_t cfa,
|
||||
const typename CFI_Parser<A, R>::RegisterLocation &savedReg) {
|
||||
switch (savedReg.location) {
|
||||
case CFI_Parser<A, R>::kRegisterInCFA:
|
||||
return addressSpace.getP(cfa + savedReg.value);
|
||||
|
||||
case CFI_Parser<A, R>::kRegisterAtExpression:
|
||||
return addressSpace.getP(
|
||||
evaluateExpression(savedReg.value, addressSpace, registers, cfa));
|
||||
|
||||
case CFI_Parser<A, R>::kRegisterIsExpression:
|
||||
return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
|
||||
|
||||
case CFI_Parser<A, R>::kRegisterInRegister:
|
||||
return registers.getRegister(savedReg.value);
|
||||
|
||||
case CFI_Parser<A, R>::kRegisterUnused:
|
||||
case CFI_Parser<A, R>::kRegisterOffsetFromCFA:
|
||||
assert(0 && "unsupported restore location for register");
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template <typename A, typename R>
|
||||
typename DwarfInstructions<A, R>::pint_t
|
||||
DwarfInstructions<A, R>::computeRegisterLocation(
|
||||
A &addressSpace, const R ®isters, pint_t cfa,
|
||||
const typename CFI_Parser<A, R>::RegisterLocation &savedReg) {
|
||||
switch (savedReg.location) {
|
||||
case CFI_Parser<A, R>::kRegisterInCFA:
|
||||
return cfa + savedReg.value;
|
||||
|
||||
case CFI_Parser<A, R>::kRegisterAtExpression:
|
||||
return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
|
||||
|
||||
case CFI_Parser<A, R>::kRegisterIsExpression:
|
||||
case CFI_Parser<A, R>::kRegisterUnused:
|
||||
case CFI_Parser<A, R>::kRegisterOffsetFromCFA:
|
||||
case CFI_Parser<A, R>::kRegisterInRegister:
|
||||
assert(0 && "unsupported restore location for float/vector register");
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template <typename A, typename R>
|
||||
step_result DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
||||
pint_t fdeStart,
|
||||
R ®isters,
|
||||
unw_proc_info_t *ctx) {
|
||||
typename CFI_Parser<A, R>::FDE_Info fdeInfo;
|
||||
typename CFI_Parser<A, R>::CIE_Info cieInfo;
|
||||
if (!CFI_Parser<A, R>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo,
|
||||
ctx))
|
||||
return UNW_STEP_FAILED;
|
||||
|
||||
typename CFI_Parser<A, R>::PrologInfo prolog;
|
||||
if (!CFI_Parser<A, R>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo,
|
||||
pc, &prolog, ctx))
|
||||
return UNW_STEP_FAILED;
|
||||
|
||||
// Create working copy of the register set.
|
||||
R newRegisters = registers;
|
||||
|
||||
// Get pointer to CFA by the architecture-specific code.
|
||||
pint_t cfa = getCFA(addressSpace, prolog, registers);
|
||||
|
||||
// Restore registers according to DWARF instructions
|
||||
pint_t returnAddress = 0;
|
||||
for (int i = 0; i <= lastRestoreReg(newRegisters); ++i) {
|
||||
if (prolog.savedRegisters[i].location == CFI_Parser<A, R>::kRegisterUnused)
|
||||
continue;
|
||||
if (isReturnAddressRegister(i, registers))
|
||||
returnAddress = getSavedRegister(addressSpace, registers, cfa,
|
||||
prolog.savedRegisters[i]);
|
||||
else if (registers.validRegister(i))
|
||||
newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa,
|
||||
prolog.savedRegisters[i]));
|
||||
else if (registers.validFloatVectorRegister(i))
|
||||
newRegisters.copyFloatVectorRegister(
|
||||
i, computeRegisterLocation(addressSpace, registers, cfa,
|
||||
prolog.savedRegisters[i]));
|
||||
else
|
||||
return UNW_STEP_FAILED;
|
||||
}
|
||||
|
||||
// The CFA is defined as the stack pointer at the call site.
|
||||
// Therefore the SP is restored by setting it to the CFA.
|
||||
newRegisters.setSP(cfa);
|
||||
newRegisters.setIP(returnAddress);
|
||||
|
||||
// Now replace register set with the working copy.
|
||||
registers = newRegisters;
|
||||
|
||||
return UNW_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
template <typename A, typename R>
|
||||
typename A::pint_t
|
||||
DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
|
||||
const R ®isters,
|
||||
pint_t initialStackValue) {
|
||||
pint_t p = expression;
|
||||
pint_t expressionEnd = expression + 20; // Rough estimate
|
||||
uint64_t length = addressSpace.getULEB128(p, expressionEnd);
|
||||
expressionEnd = p + length;
|
||||
pint_t stack[100];
|
||||
pint_t *sp = stack;
|
||||
*(++sp) = initialStackValue;
|
||||
|
||||
while (p < expressionEnd) {
|
||||
uint8_t opcode = addressSpace.get8(p++);
|
||||
sint_t svalue;
|
||||
pint_t value;
|
||||
uint32_t reg;
|
||||
switch (opcode) {
|
||||
case DW_OP_addr:
|
||||
// push immediate address sized value
|
||||
value = addressSpace.getP(p);
|
||||
p += sizeof(pint_t);
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_deref:
|
||||
// pop stack, dereference, push result
|
||||
value = *sp--;
|
||||
*(++sp) = addressSpace.getP(value);
|
||||
break;
|
||||
|
||||
case DW_OP_const1u:
|
||||
// push immediate 1 byte value
|
||||
value = addressSpace.get8(p);
|
||||
p += 1;
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_const1s:
|
||||
// push immediate 1 byte signed value
|
||||
svalue = (int8_t)addressSpace.get8(p);
|
||||
p += 1;
|
||||
*(++sp) = svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_const2u:
|
||||
// push immediate 2 byte value
|
||||
value = addressSpace.get16(p);
|
||||
p += 2;
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_const2s:
|
||||
// push immediate 2 byte signed value
|
||||
svalue = (int16_t)addressSpace.get16(p);
|
||||
p += 2;
|
||||
*(++sp) = svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_const4u:
|
||||
// push immediate 4 byte value
|
||||
value = addressSpace.get32(p);
|
||||
p += 4;
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_const4s:
|
||||
// push immediate 4 byte signed value
|
||||
svalue = (int32_t)addressSpace.get32(p);
|
||||
p += 4;
|
||||
*(++sp) = svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_const8u:
|
||||
// push immediate 8 byte value
|
||||
value = addressSpace.get64(p);
|
||||
p += 8;
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_const8s:
|
||||
// push immediate 8 byte signed value
|
||||
value = (int32_t)addressSpace.get64(p);
|
||||
p += 8;
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_constu:
|
||||
// push immediate ULEB128 value
|
||||
value = addressSpace.getULEB128(p, expressionEnd);
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_consts:
|
||||
// push immediate SLEB128 value
|
||||
svalue = addressSpace.getSLEB128(p, expressionEnd);
|
||||
*(++sp) = svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_dup:
|
||||
// push top of stack
|
||||
value = *sp;
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_drop:
|
||||
// pop
|
||||
--sp;
|
||||
break;
|
||||
|
||||
case DW_OP_over:
|
||||
// dup second
|
||||
value = sp[-1];
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_pick:
|
||||
// pick from
|
||||
reg = addressSpace.get8(p);
|
||||
p += 1;
|
||||
value = sp[-reg];
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_swap:
|
||||
// swap top two
|
||||
value = sp[0];
|
||||
sp[0] = sp[-1];
|
||||
sp[-1] = value;
|
||||
break;
|
||||
|
||||
case DW_OP_rot:
|
||||
// rotate top three
|
||||
value = sp[0];
|
||||
sp[0] = sp[-1];
|
||||
sp[-1] = sp[-2];
|
||||
sp[-2] = value;
|
||||
break;
|
||||
|
||||
case DW_OP_xderef:
|
||||
// pop stack, dereference, push result
|
||||
value = *sp--;
|
||||
*sp = *((uint64_t *)value);
|
||||
break;
|
||||
|
||||
case DW_OP_abs:
|
||||
svalue = *sp;
|
||||
if (svalue < 0)
|
||||
*sp = -svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_and:
|
||||
value = *sp--;
|
||||
*sp &= value;
|
||||
break;
|
||||
|
||||
case DW_OP_div:
|
||||
svalue = *sp--;
|
||||
*sp = *sp / svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_minus:
|
||||
svalue = *sp--;
|
||||
*sp = *sp - svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_mod:
|
||||
svalue = *sp--;
|
||||
*sp = *sp % svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_mul:
|
||||
svalue = *sp--;
|
||||
*sp = *sp * svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_neg:
|
||||
*sp = 0 - *sp;
|
||||
break;
|
||||
|
||||
case DW_OP_not:
|
||||
svalue = *sp;
|
||||
*sp = ~svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_or:
|
||||
value = *sp--;
|
||||
*sp |= value;
|
||||
break;
|
||||
|
||||
case DW_OP_plus:
|
||||
value = *sp--;
|
||||
*sp += value;
|
||||
break;
|
||||
|
||||
case DW_OP_plus_uconst:
|
||||
// pop stack, add uelb128 constant, push result
|
||||
*sp += addressSpace.getULEB128(p, expressionEnd);
|
||||
break;
|
||||
|
||||
case DW_OP_shl:
|
||||
value = *sp--;
|
||||
*sp = *sp << value;
|
||||
break;
|
||||
|
||||
case DW_OP_shr:
|
||||
value = *sp--;
|
||||
*sp = *sp >> value;
|
||||
break;
|
||||
|
||||
case DW_OP_shra:
|
||||
value = *sp--;
|
||||
svalue = *sp;
|
||||
*sp = svalue >> value;
|
||||
break;
|
||||
|
||||
case DW_OP_xor:
|
||||
value = *sp--;
|
||||
*sp ^= value;
|
||||
break;
|
||||
|
||||
case DW_OP_skip:
|
||||
svalue = (int16_t)addressSpace.get16(p);
|
||||
p += 2;
|
||||
p += svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_bra:
|
||||
svalue = (int16_t)addressSpace.get16(p);
|
||||
p += 2;
|
||||
if (*sp--)
|
||||
p += svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_eq:
|
||||
value = *sp--;
|
||||
*sp = (*sp == value);
|
||||
break;
|
||||
|
||||
case DW_OP_ge:
|
||||
value = *sp--;
|
||||
*sp = (*sp >= value);
|
||||
break;
|
||||
|
||||
case DW_OP_gt:
|
||||
value = *sp--;
|
||||
*sp = (*sp > value);
|
||||
break;
|
||||
|
||||
case DW_OP_le:
|
||||
value = *sp--;
|
||||
*sp = (*sp <= value);
|
||||
break;
|
||||
|
||||
case DW_OP_lt:
|
||||
value = *sp--;
|
||||
*sp = (*sp < value);
|
||||
break;
|
||||
|
||||
case DW_OP_ne:
|
||||
value = *sp--;
|
||||
*sp = (*sp != value);
|
||||
break;
|
||||
|
||||
case DW_OP_lit0:
|
||||
case DW_OP_lit1:
|
||||
case DW_OP_lit2:
|
||||
case DW_OP_lit3:
|
||||
case DW_OP_lit4:
|
||||
case DW_OP_lit5:
|
||||
case DW_OP_lit6:
|
||||
case DW_OP_lit7:
|
||||
case DW_OP_lit8:
|
||||
case DW_OP_lit9:
|
||||
case DW_OP_lit10:
|
||||
case DW_OP_lit11:
|
||||
case DW_OP_lit12:
|
||||
case DW_OP_lit13:
|
||||
case DW_OP_lit14:
|
||||
case DW_OP_lit15:
|
||||
case DW_OP_lit16:
|
||||
case DW_OP_lit17:
|
||||
case DW_OP_lit18:
|
||||
case DW_OP_lit19:
|
||||
case DW_OP_lit20:
|
||||
case DW_OP_lit21:
|
||||
case DW_OP_lit22:
|
||||
case DW_OP_lit23:
|
||||
case DW_OP_lit24:
|
||||
case DW_OP_lit25:
|
||||
case DW_OP_lit26:
|
||||
case DW_OP_lit27:
|
||||
case DW_OP_lit28:
|
||||
case DW_OP_lit29:
|
||||
case DW_OP_lit30:
|
||||
case DW_OP_lit31:
|
||||
value = opcode - DW_OP_lit0;
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_reg0:
|
||||
case DW_OP_reg1:
|
||||
case DW_OP_reg2:
|
||||
case DW_OP_reg3:
|
||||
case DW_OP_reg4:
|
||||
case DW_OP_reg5:
|
||||
case DW_OP_reg6:
|
||||
case DW_OP_reg7:
|
||||
case DW_OP_reg8:
|
||||
case DW_OP_reg9:
|
||||
case DW_OP_reg10:
|
||||
case DW_OP_reg11:
|
||||
case DW_OP_reg12:
|
||||
case DW_OP_reg13:
|
||||
case DW_OP_reg14:
|
||||
case DW_OP_reg15:
|
||||
case DW_OP_reg16:
|
||||
case DW_OP_reg17:
|
||||
case DW_OP_reg18:
|
||||
case DW_OP_reg19:
|
||||
case DW_OP_reg20:
|
||||
case DW_OP_reg21:
|
||||
case DW_OP_reg22:
|
||||
case DW_OP_reg23:
|
||||
case DW_OP_reg24:
|
||||
case DW_OP_reg25:
|
||||
case DW_OP_reg26:
|
||||
case DW_OP_reg27:
|
||||
case DW_OP_reg28:
|
||||
case DW_OP_reg29:
|
||||
case DW_OP_reg30:
|
||||
case DW_OP_reg31:
|
||||
reg = opcode - DW_OP_reg0;
|
||||
*(++sp) = registers.getRegister(reg);
|
||||
break;
|
||||
|
||||
case DW_OP_regx:
|
||||
reg = addressSpace.getULEB128(p, expressionEnd);
|
||||
*(++sp) = registers.getRegister(reg);
|
||||
break;
|
||||
|
||||
case DW_OP_breg0:
|
||||
case DW_OP_breg1:
|
||||
case DW_OP_breg2:
|
||||
case DW_OP_breg3:
|
||||
case DW_OP_breg4:
|
||||
case DW_OP_breg5:
|
||||
case DW_OP_breg6:
|
||||
case DW_OP_breg7:
|
||||
case DW_OP_breg8:
|
||||
case DW_OP_breg9:
|
||||
case DW_OP_breg10:
|
||||
case DW_OP_breg11:
|
||||
case DW_OP_breg12:
|
||||
case DW_OP_breg13:
|
||||
case DW_OP_breg14:
|
||||
case DW_OP_breg15:
|
||||
case DW_OP_breg16:
|
||||
case DW_OP_breg17:
|
||||
case DW_OP_breg18:
|
||||
case DW_OP_breg19:
|
||||
case DW_OP_breg20:
|
||||
case DW_OP_breg21:
|
||||
case DW_OP_breg22:
|
||||
case DW_OP_breg23:
|
||||
case DW_OP_breg24:
|
||||
case DW_OP_breg25:
|
||||
case DW_OP_breg26:
|
||||
case DW_OP_breg27:
|
||||
case DW_OP_breg28:
|
||||
case DW_OP_breg29:
|
||||
case DW_OP_breg30:
|
||||
case DW_OP_breg31:
|
||||
reg = opcode - DW_OP_breg0;
|
||||
svalue = addressSpace.getSLEB128(p, expressionEnd);
|
||||
*(++sp) = registers.getRegister(reg) + svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_bregx:
|
||||
reg = addressSpace.getULEB128(p, expressionEnd);
|
||||
svalue = addressSpace.getSLEB128(p, expressionEnd);
|
||||
*(++sp) = registers.getRegister(reg) + svalue;
|
||||
break;
|
||||
|
||||
case DW_OP_deref_size:
|
||||
// pop stack, dereference, push result
|
||||
value = *sp--;
|
||||
switch (addressSpace.get8(p++)) {
|
||||
case 1:
|
||||
value = addressSpace.get8(value);
|
||||
break;
|
||||
case 2:
|
||||
value = addressSpace.get16(value);
|
||||
break;
|
||||
case 4:
|
||||
value = addressSpace.get32(value);
|
||||
break;
|
||||
case 8:
|
||||
value = addressSpace.get64(value);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "DW_OP_deref_size with bad size");
|
||||
}
|
||||
*(++sp) = value;
|
||||
break;
|
||||
|
||||
case DW_OP_fbreg:
|
||||
case DW_OP_piece:
|
||||
case DW_OP_xderef_size:
|
||||
case DW_OP_nop:
|
||||
case DW_OP_push_object_addres:
|
||||
case DW_OP_call2:
|
||||
case DW_OP_call4:
|
||||
case DW_OP_call_ref:
|
||||
default:
|
||||
assert(0 && "dwarf opcode not implemented");
|
||||
}
|
||||
}
|
||||
return *sp;
|
||||
}
|
||||
|
||||
} // namespace _Unwind
|
||||
|
||||
#endif // __DWARF_INSTRUCTIONS_HPP__
|
529
sys/lib/libunwind/DwarfParser.hpp
Normal file
529
sys/lib/libunwind/DwarfParser.hpp
Normal file
|
@ -0,0 +1,529 @@
|
|||
//===--------------------------- DwarfParser.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.
|
||||
//
|
||||
//
|
||||
// Parses DWARF CFIs (FDEs and CIEs).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __DWARF_PARSER_HPP__
|
||||
#define __DWARF_PARSER_HPP__
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "dwarf2.h"
|
||||
#include "AddressSpace.hpp"
|
||||
|
||||
namespace _Unwind {
|
||||
|
||||
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
|
||||
/// See Dwarf Spec for details:
|
||||
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
|
||||
///
|
||||
template <typename A, typename R> class CFI_Parser {
|
||||
public:
|
||||
typedef typename A::pint_t pint_t;
|
||||
|
||||
/// Information encoded in a CIE (Common Information Entry)
|
||||
struct CIE_Info {
|
||||
pint_t cieStart;
|
||||
pint_t cieLength;
|
||||
pint_t cieInstructions;
|
||||
pint_t personality;
|
||||
uint32_t codeAlignFactor;
|
||||
int dataAlignFactor;
|
||||
uint8_t pointerEncoding;
|
||||
uint8_t lsdaEncoding;
|
||||
uint8_t personalityEncoding;
|
||||
uint8_t personalityOffsetInCIE;
|
||||
bool isSignalFrame;
|
||||
bool fdesHaveAugmentationData;
|
||||
};
|
||||
|
||||
/// Information about an FDE (Frame Description Entry)
|
||||
struct FDE_Info {
|
||||
pint_t fdeStart;
|
||||
pint_t fdeLength;
|
||||
pint_t fdeInstructions;
|
||||
pint_t pcStart;
|
||||
pint_t pcEnd;
|
||||
pint_t lsda;
|
||||
};
|
||||
|
||||
/// Information about a frame layout and registers saved determined
|
||||
/// by "running" the DWARF FDE "instructions"
|
||||
enum {
|
||||
kMaxRegisterNumber = R::LAST_REGISTER + 1
|
||||
};
|
||||
enum RegisterSavedWhere {
|
||||
kRegisterUnused,
|
||||
kRegisterInCFA,
|
||||
kRegisterOffsetFromCFA,
|
||||
kRegisterInRegister,
|
||||
kRegisterAtExpression,
|
||||
kRegisterIsExpression,
|
||||
};
|
||||
struct RegisterLocation {
|
||||
RegisterSavedWhere location;
|
||||
int64_t value;
|
||||
};
|
||||
struct PrologInfo {
|
||||
uint32_t cfaRegister;
|
||||
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
|
||||
int64_t cfaExpression; // CFA = expression
|
||||
uint32_t spExtraArgSize;
|
||||
uint32_t codeOffsetAtStackDecrement;
|
||||
RegisterLocation savedRegisters[kMaxRegisterNumber];
|
||||
};
|
||||
|
||||
struct PrologInfoStackEntry {
|
||||
PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
|
||||
: next(n), info(i) {}
|
||||
PrologInfoStackEntry *next;
|
||||
PrologInfo info;
|
||||
};
|
||||
|
||||
static void findPCRange(A &, pint_t, pint_t &, pint_t &);
|
||||
|
||||
static bool decodeFDE(A &, pint_t, FDE_Info *, CIE_Info *,
|
||||
unw_proc_info_t *ctx);
|
||||
static bool parseFDEInstructions(A &, const FDE_Info &, const CIE_Info &,
|
||||
pint_t, PrologInfo *, unw_proc_info_t *ctx);
|
||||
|
||||
static bool parseCIE(A &, pint_t, CIE_Info *);
|
||||
|
||||
private:
|
||||
static bool parseInstructions(A &, pint_t, pint_t, const CIE_Info &, pint_t,
|
||||
PrologInfoStackEntry *&, PrologInfo *,
|
||||
unw_proc_info_t *ctx);
|
||||
};
|
||||
|
||||
///
|
||||
/// Parse a FDE and return the last PC it covers.
|
||||
///
|
||||
template <typename A, typename R>
|
||||
void CFI_Parser<A, R>::findPCRange(A &addressSpace, pint_t fde, pint_t &pcStart,
|
||||
pint_t &pcEnd) {
|
||||
pcStart = 0;
|
||||
pcEnd = 0;
|
||||
pint_t p = fde;
|
||||
uint64_t cfiLength = addressSpace.get32(p);
|
||||
p += 4;
|
||||
if (cfiLength == 0xffffffff) {
|
||||
// 0xffffffff means length is really the next 8 Bytes.
|
||||
cfiLength = addressSpace.get64(p);
|
||||
p += 8;
|
||||
}
|
||||
if (cfiLength == 0)
|
||||
return;
|
||||
uint32_t ciePointer = addressSpace.get32(p);
|
||||
if (ciePointer == 0)
|
||||
return;
|
||||
pint_t nextCFI = p + cfiLength;
|
||||
pint_t cieStart = p - ciePointer;
|
||||
typename CFI_Parser<A, R>::CIE_Info cieInfo;
|
||||
if (!parseCIE(addressSpace, cieStart, &cieInfo))
|
||||
return;
|
||||
p += 4;
|
||||
// Parse pc begin and range.
|
||||
pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding, NULL);
|
||||
pcEnd = pcStart + addressSpace.getEncodedP(
|
||||
p, nextCFI, cieInfo.pointerEncoding & 0x0F, NULL);
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a FDE into a CIE_Info and an FDE_Info
|
||||
///
|
||||
template <typename A, typename R>
|
||||
bool CFI_Parser<A, R>::decodeFDE(A &addressSpace, pint_t fdeStart,
|
||||
FDE_Info *fdeInfo, CIE_Info *cieInfo,
|
||||
unw_proc_info_t *ctx) {
|
||||
pint_t p = fdeStart;
|
||||
uint64_t cfiLength = addressSpace.get32(p);
|
||||
p += 4;
|
||||
if (cfiLength == 0xffffffff) {
|
||||
// 0xffffffff means length is really the next 8 Bytes.
|
||||
cfiLength = addressSpace.get64(p);
|
||||
p += 8;
|
||||
}
|
||||
if (cfiLength == 0)
|
||||
return false;
|
||||
uint32_t ciePointer = addressSpace.get32(p);
|
||||
if (ciePointer == 0)
|
||||
return false;
|
||||
pint_t nextCFI = p + cfiLength;
|
||||
pint_t cieStart = p - ciePointer;
|
||||
if (!parseCIE(addressSpace, cieStart, cieInfo))
|
||||
return false;
|
||||
p += 4;
|
||||
// Parse pc begin and range.
|
||||
pint_t pcStart =
|
||||
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding, ctx);
|
||||
pint_t pcRange = addressSpace.getEncodedP(
|
||||
p, nextCFI, cieInfo->pointerEncoding & 0x0F, ctx);
|
||||
// Parse rest of info.
|
||||
fdeInfo->lsda = 0;
|
||||
// Check for augmentation length
|
||||
if (cieInfo->fdesHaveAugmentationData) {
|
||||
uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
|
||||
pint_t endOfAug = p + augLen;
|
||||
if (cieInfo->lsdaEncoding != 0) {
|
||||
// Peek at value (without indirection). Zero means no LSDA.
|
||||
pint_t lsdaStart = p;
|
||||
if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F,
|
||||
ctx) != 0) {
|
||||
// Reset pointer and re-parse LSDA address.
|
||||
p = lsdaStart;
|
||||
fdeInfo->lsda =
|
||||
addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding, ctx);
|
||||
}
|
||||
}
|
||||
p = endOfAug;
|
||||
}
|
||||
fdeInfo->fdeStart = fdeStart;
|
||||
fdeInfo->fdeLength = nextCFI - fdeStart;
|
||||
fdeInfo->fdeInstructions = p;
|
||||
fdeInfo->pcStart = pcStart;
|
||||
fdeInfo->pcEnd = pcStart + pcRange;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Extract info from a CIE
|
||||
template <typename A, typename R>
|
||||
bool CFI_Parser<A, R>::parseCIE(A &addressSpace, pint_t cie,
|
||||
CIE_Info *cieInfo) {
|
||||
cieInfo->pointerEncoding = 0;
|
||||
cieInfo->lsdaEncoding = 0;
|
||||
cieInfo->personalityEncoding = 0;
|
||||
cieInfo->personalityOffsetInCIE = 0;
|
||||
cieInfo->personality = 0;
|
||||
cieInfo->codeAlignFactor = 0;
|
||||
cieInfo->dataAlignFactor = 0;
|
||||
cieInfo->isSignalFrame = false;
|
||||
cieInfo->fdesHaveAugmentationData = false;
|
||||
cieInfo->cieStart = cie;
|
||||
pint_t p = cie;
|
||||
uint64_t cieLength = addressSpace.get32(p);
|
||||
p += 4;
|
||||
pint_t cieContentEnd = p + cieLength;
|
||||
if (cieLength == 0xffffffff) {
|
||||
// 0xffffffff means length is really the next 8 Bytes.
|
||||
cieLength = addressSpace.get64(p);
|
||||
p += 8;
|
||||
cieContentEnd = p + cieLength;
|
||||
}
|
||||
if (cieLength == 0)
|
||||
return true;
|
||||
// CIE ID is always 0
|
||||
if (addressSpace.get32(p) != 0)
|
||||
return false;
|
||||
p += 4;
|
||||
// Version is always 1 or 3
|
||||
uint8_t version = addressSpace.get8(p);
|
||||
if (version != 1 && version != 3)
|
||||
return false;
|
||||
++p;
|
||||
// Save start of augmentation string and find end.
|
||||
pint_t strStart = p;
|
||||
while (addressSpace.get8(p) != 0)
|
||||
++p;
|
||||
++p;
|
||||
// Parse code aligment factor
|
||||
cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
|
||||
// Parse data alignment factor
|
||||
cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
|
||||
// Parse return address register
|
||||
addressSpace.getULEB128(p, cieContentEnd);
|
||||
// Parse augmentation data based on augmentation string.
|
||||
if (addressSpace.get8(strStart) == 'z') {
|
||||
// parse augmentation data length
|
||||
addressSpace.getULEB128(p, cieContentEnd);
|
||||
for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
|
||||
switch (addressSpace.get8(s)) {
|
||||
case 'z':
|
||||
cieInfo->fdesHaveAugmentationData = true;
|
||||
break;
|
||||
case 'P':
|
||||
cieInfo->personalityEncoding = addressSpace.get8(p);
|
||||
++p;
|
||||
cieInfo->personalityOffsetInCIE = p - cie;
|
||||
cieInfo->personality = addressSpace.getEncodedP(
|
||||
p, cieContentEnd, cieInfo->personalityEncoding, NULL);
|
||||
break;
|
||||
case 'L':
|
||||
cieInfo->lsdaEncoding = addressSpace.get8(p);
|
||||
++p;
|
||||
break;
|
||||
case 'R':
|
||||
cieInfo->pointerEncoding = addressSpace.get8(p);
|
||||
++p;
|
||||
break;
|
||||
case 'S':
|
||||
cieInfo->isSignalFrame = true;
|
||||
break;
|
||||
default:
|
||||
// ignore unknown letters
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
|
||||
cieInfo->cieInstructions = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// "Run" the dwarf instructions and create the abstact PrologInfo for an FDE.
|
||||
template <typename A, typename R>
|
||||
bool CFI_Parser<A, R>::parseFDEInstructions(A &addressSpace,
|
||||
const FDE_Info &fdeInfo,
|
||||
const CIE_Info &cieInfo,
|
||||
pint_t upToPC, PrologInfo *results,
|
||||
unw_proc_info_t *ctx) {
|
||||
// Clear results.
|
||||
memset(results, 0, sizeof(*results));
|
||||
PrologInfoStackEntry *rememberStack = NULL;
|
||||
|
||||
// First parse the CIE then FDE instructions.
|
||||
if (!parseInstructions(addressSpace, cieInfo.cieInstructions,
|
||||
cieInfo.cieStart + cieInfo.cieLength, cieInfo,
|
||||
(pint_t)(-1), rememberStack, results, ctx))
|
||||
return false;
|
||||
return parseInstructions(addressSpace, fdeInfo.fdeInstructions,
|
||||
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
|
||||
upToPC - fdeInfo.pcStart, rememberStack, results,
|
||||
ctx);
|
||||
}
|
||||
|
||||
/// "Run" the DWARF instructions.
|
||||
template <typename A, typename R>
|
||||
bool
|
||||
CFI_Parser<A, R>::parseInstructions(A &addressSpace, pint_t instructions,
|
||||
pint_t instructionsEnd,
|
||||
const CIE_Info &cieInfo, pint_t pcoffset,
|
||||
PrologInfoStackEntry *&rememberStack,
|
||||
PrologInfo *results, unw_proc_info_t *ctx) {
|
||||
pint_t p = instructions;
|
||||
uint32_t codeOffset = 0;
|
||||
PrologInfo initialState = *results;
|
||||
|
||||
// See Dwarf Spec, section 6.4.2 for details on unwind opcodes.
|
||||
while (p < instructionsEnd && codeOffset < pcoffset) {
|
||||
uint64_t reg;
|
||||
uint64_t reg2;
|
||||
int64_t offset;
|
||||
uint64_t length;
|
||||
uint8_t opcode = addressSpace.get8(p);
|
||||
uint8_t operand;
|
||||
PrologInfoStackEntry *entry;
|
||||
++p;
|
||||
switch (opcode) {
|
||||
case DW_CFA_nop:
|
||||
break;
|
||||
case DW_CFA_set_loc:
|
||||
codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
|
||||
cieInfo.pointerEncoding, ctx);
|
||||
break;
|
||||
case DW_CFA_advance_loc1:
|
||||
codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
|
||||
p += 1;
|
||||
break;
|
||||
case DW_CFA_advance_loc2:
|
||||
codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
|
||||
p += 2;
|
||||
break;
|
||||
case DW_CFA_advance_loc4:
|
||||
codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
|
||||
p += 4;
|
||||
break;
|
||||
case DW_CFA_offset_extended:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
offset =
|
||||
addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
break;
|
||||
case DW_CFA_restore_extended:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->savedRegisters[reg] = initialState.savedRegisters[reg];
|
||||
break;
|
||||
case DW_CFA_undefined:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->savedRegisters[reg].location = kRegisterUnused;
|
||||
break;
|
||||
case DW_CFA_same_value:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
// "same value" means register was stored in frame, but its current
|
||||
// value has not changed, so no need to restore from frame.
|
||||
// We model this as if the register was never saved.
|
||||
results->savedRegisters[reg].location = kRegisterUnused;
|
||||
break;
|
||||
case DW_CFA_register:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
reg2 = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
if (reg2 > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->savedRegisters[reg].location = kRegisterInRegister;
|
||||
results->savedRegisters[reg].value = reg2;
|
||||
break;
|
||||
case DW_CFA_remember_state:
|
||||
// avoid operator new, because that would be an upward dependency
|
||||
entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
|
||||
if (entry == NULL)
|
||||
return false;
|
||||
|
||||
entry->next = rememberStack;
|
||||
entry->info = *results;
|
||||
rememberStack = entry;
|
||||
break;
|
||||
case DW_CFA_restore_state:
|
||||
if (rememberStack == NULL)
|
||||
return false;
|
||||
{
|
||||
PrologInfoStackEntry *top = rememberStack;
|
||||
*results = top->info;
|
||||
rememberStack = top->next;
|
||||
free((char *)top);
|
||||
}
|
||||
break;
|
||||
case DW_CFA_def_cfa:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
offset = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->cfaRegister = reg;
|
||||
results->cfaRegisterOffset = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_register:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->cfaRegister = reg;
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset:
|
||||
results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
|
||||
results->codeOffsetAtStackDecrement = codeOffset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_expression:
|
||||
results->cfaRegister = 0;
|
||||
results->cfaExpression = p;
|
||||
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||
p += length;
|
||||
break;
|
||||
case DW_CFA_expression:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->savedRegisters[reg].location = kRegisterAtExpression;
|
||||
results->savedRegisters[reg].value = p;
|
||||
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||
p += length;
|
||||
break;
|
||||
case DW_CFA_offset_extended_sf:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
offset =
|
||||
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_sf:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
offset =
|
||||
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->cfaRegister = reg;
|
||||
results->cfaRegisterOffset = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset_sf:
|
||||
results->cfaRegisterOffset =
|
||||
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
results->codeOffsetAtStackDecrement = codeOffset;
|
||||
break;
|
||||
case DW_CFA_val_offset:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
offset =
|
||||
addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
break;
|
||||
case DW_CFA_val_offset_sf:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
offset =
|
||||
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
break;
|
||||
case DW_CFA_val_expression:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->savedRegisters[reg].location = kRegisterIsExpression;
|
||||
results->savedRegisters[reg].value = p;
|
||||
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||
p += length;
|
||||
break;
|
||||
case DW_CFA_GNU_args_size:
|
||||
offset = addressSpace.getULEB128(p, instructionsEnd);
|
||||
results->spExtraArgSize = offset;
|
||||
break;
|
||||
case DW_CFA_GNU_negative_offset_extended:
|
||||
reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
offset =
|
||||
addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = -offset;
|
||||
break;
|
||||
default:
|
||||
operand = opcode & 0x3F;
|
||||
switch (opcode & 0xC0) {
|
||||
case DW_CFA_offset:
|
||||
reg = R::dwarf2regno(operand);
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
offset = addressSpace.getULEB128(p, instructionsEnd) *
|
||||
cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
break;
|
||||
case DW_CFA_advance_loc:
|
||||
codeOffset += operand * cieInfo.codeAlignFactor;
|
||||
break;
|
||||
case DW_CFA_restore:
|
||||
reg = R::dwarf2regno(operand);
|
||||
if (reg > kMaxRegisterNumber)
|
||||
return false;
|
||||
results->savedRegisters[reg] = initialState.savedRegisters[reg];
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace _Unwind
|
||||
|
||||
#endif // __DWARF_PARSER_HPP__
|
76
sys/lib/libunwind/LICENSE.TXT
Normal file
76
sys/lib/libunwind/LICENSE.TXT
Normal file
|
@ -0,0 +1,76 @@
|
|||
==============================================================================
|
||||
libc++abi License
|
||||
==============================================================================
|
||||
|
||||
The libc++abi library is dual licensed under both the University of Illinois
|
||||
"BSD-Like" license and the MIT license. As a user of this code you may choose
|
||||
to use it under either license. As a contributor, you agree to allow your code
|
||||
to be used under both.
|
||||
|
||||
Full text of the relevant licenses is included below.
|
||||
|
||||
==============================================================================
|
||||
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
10
sys/lib/libunwind/Makefile.inc
Normal file
10
sys/lib/libunwind/Makefile.inc
Normal file
|
@ -0,0 +1,10 @@
|
|||
# $NetBSD: Makefile.inc,v 1.1 2013/10/14 01:14:57 joerg Exp $
|
||||
|
||||
.PATH: ${NETBSDSRCDIR}/sys/lib/libunwind
|
||||
|
||||
SRCS+= libunwind.cxx \
|
||||
unwind_registers.S
|
||||
|
||||
INCS+= unwind.h
|
||||
|
||||
COPTS.libuwind.cxx+= -funwind-tables -fno-rtti -fno-exceptions -fvisibility=hidden -Wno-old-style-cast
|
234
sys/lib/libunwind/Registers.hpp
Normal file
234
sys/lib/libunwind/Registers.hpp
Normal file
|
@ -0,0 +1,234 @@
|
|||
//===----------------------------- Registers.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.
|
||||
//
|
||||
//
|
||||
// Models register sets for supported processors.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef __REGISTERS_HPP__
|
||||
#define __REGISTERS_HPP__
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
namespace _Unwind {
|
||||
|
||||
enum {
|
||||
REGNO_X86_EAX = 0,
|
||||
REGNO_X86_ECX = 1,
|
||||
REGNO_X86_EDX = 2,
|
||||
REGNO_X86_EBX = 3,
|
||||
REGNO_X86_ESP = 4,
|
||||
REGNO_X86_EBP = 5,
|
||||
REGNO_X86_ESI = 6,
|
||||
REGNO_X86_EDI = 7,
|
||||
REGNO_X86_EIP = 8,
|
||||
};
|
||||
|
||||
class Registers_x86 {
|
||||
public:
|
||||
enum {
|
||||
LAST_RESTORE_REG = REGNO_X86_EIP,
|
||||
IP_PSEUDO_REG = REGNO_X86_EIP,
|
||||
LAST_REGISTER = REGNO_X86_EIP,
|
||||
};
|
||||
|
||||
__dso_hidden Registers_x86();
|
||||
|
||||
static int dwarf2regno(int num) { return num; }
|
||||
|
||||
bool validRegister(int num) const {
|
||||
return num >= REGNO_X86_EAX && num <= REGNO_X86_EDI;
|
||||
}
|
||||
|
||||
uint32_t getRegister(int num) const {
|
||||
assert(validRegister(num));
|
||||
return reg[num];
|
||||
}
|
||||
|
||||
void setRegister(int num, uint32_t value) {
|
||||
assert(validRegister(num));
|
||||
reg[num] = value;
|
||||
}
|
||||
|
||||
uint32_t getIP() const { return reg[REGNO_X86_EIP]; }
|
||||
|
||||
void setIP(uint32_t value) { reg[REGNO_X86_EIP] = value; }
|
||||
|
||||
uint32_t getSP() const { return reg[REGNO_X86_ESP]; }
|
||||
|
||||
void setSP(uint32_t value) { reg[REGNO_X86_ESP] = value; }
|
||||
|
||||
bool validFloatVectorRegister(int num) const { return false; }
|
||||
|
||||
void copyFloatVectorRegister(int num, uint32_t addr) {
|
||||
}
|
||||
|
||||
__dso_hidden void jumpto() const __dead;
|
||||
|
||||
private:
|
||||
uint32_t reg[REGNO_X86_EIP + 1];
|
||||
};
|
||||
|
||||
enum {
|
||||
REGNO_X86_64_RAX = 0,
|
||||
REGNO_X86_64_RDX = 1,
|
||||
REGNO_X86_64_RCX = 2,
|
||||
REGNO_X86_64_RBX = 3,
|
||||
REGNO_X86_64_RSI = 4,
|
||||
REGNO_X86_64_RDI = 5,
|
||||
REGNO_X86_64_RBP = 6,
|
||||
REGNO_X86_64_RSP = 7,
|
||||
REGNO_X86_64_R8 = 8,
|
||||
REGNO_X86_64_R9 = 9,
|
||||
REGNO_X86_64_R10 = 10,
|
||||
REGNO_X86_64_R11 = 11,
|
||||
REGNO_X86_64_R12 = 12,
|
||||
REGNO_X86_64_R13 = 13,
|
||||
REGNO_X86_64_R14 = 14,
|
||||
REGNO_X86_64_R15 = 15,
|
||||
REGNO_X86_64_RIP = 16,
|
||||
};
|
||||
|
||||
class Registers_x86_64 {
|
||||
public:
|
||||
enum {
|
||||
LAST_RESTORE_REG = REGNO_X86_64_RIP,
|
||||
IP_PSEUDO_REG = REGNO_X86_64_RIP,
|
||||
LAST_REGISTER = REGNO_X86_64_RIP,
|
||||
};
|
||||
|
||||
__dso_hidden Registers_x86_64();
|
||||
|
||||
static int dwarf2regno(int num) { return num; }
|
||||
|
||||
bool validRegister(int num) const {
|
||||
return num >= REGNO_X86_64_RAX && num <= REGNO_X86_64_R15;
|
||||
}
|
||||
|
||||
uint64_t getRegister(int num) const {
|
||||
assert(validRegister(num));
|
||||
return reg[num];
|
||||
}
|
||||
|
||||
void setRegister(int num, uint64_t value) {
|
||||
assert(validRegister(num));
|
||||
reg[num] = value;
|
||||
}
|
||||
|
||||
uint64_t getIP() const { return reg[REGNO_X86_64_RIP]; }
|
||||
|
||||
void setIP(uint64_t value) { reg[REGNO_X86_64_RIP] = value; }
|
||||
|
||||
uint64_t getSP() const { return reg[REGNO_X86_64_RSP]; }
|
||||
|
||||
void setSP(uint64_t value) { reg[REGNO_X86_64_RSP] = value; }
|
||||
|
||||
bool validFloatVectorRegister(int num) const { return false; }
|
||||
|
||||
void copyFloatVectorRegister(int num, uint64_t addr) {
|
||||
}
|
||||
|
||||
__dso_hidden void jumpto() const __dead;
|
||||
|
||||
private:
|
||||
uint64_t reg[REGNO_X86_64_RIP + 1];
|
||||
};
|
||||
|
||||
enum {
|
||||
DWARF_PPC32_R0 = 0,
|
||||
DWARF_PPC32_R31 = 31,
|
||||
DWARF_PPC32_F0 = 32,
|
||||
DWARF_PPC32_F31 = 63,
|
||||
DWARF_PPC32_V0 = 1124,
|
||||
DWARF_PPC32_V31 = 1155,
|
||||
DWARF_PPC32_LR = 65,
|
||||
DWARF_PPC32_CTR = 66,
|
||||
DWARF_PPC32_XER = 76,
|
||||
REGNO_PPC32_R0 = 0,
|
||||
REGNO_PPC32_R1 = 0,
|
||||
REGNO_PPC32_R31 = 31,
|
||||
REGNO_PPC32_CR = 32,
|
||||
REGNO_PPC32_LR = 33,
|
||||
REGNO_PPC32_CTR = 34,
|
||||
REGNO_PPC32_XER = 35,
|
||||
REGNO_PPC32_SRR0 = 36,
|
||||
REGNO_PPC32_F0 = REGNO_PPC32_SRR0 + 1,
|
||||
REGNO_PPC32_F31 = REGNO_PPC32_F0 + 31,
|
||||
REGNO_PPC32_V0 = REGNO_PPC32_F31 + 1,
|
||||
REGNO_PPC32_V31 = REGNO_PPC32_V0 + 31,
|
||||
};
|
||||
|
||||
class Registers_ppc32 {
|
||||
public:
|
||||
enum {
|
||||
LAST_RESTORE_REG = REGNO_PPC32_V31,
|
||||
IP_PSEUDO_REG = REGNO_PPC32_SRR0,
|
||||
LAST_REGISTER = REGNO_PPC32_V31,
|
||||
};
|
||||
|
||||
__dso_hidden Registers_ppc32();
|
||||
|
||||
static int dwarf2regno(int num) {
|
||||
if (num >= DWARF_PPC32_R0 && num <= DWARF_PPC32_R31)
|
||||
return REGNO_PPC32_R0 + (num - DWARF_PPC32_R0);
|
||||
if (num >= DWARF_PPC32_F0 && num <= DWARF_PPC32_F31)
|
||||
return REGNO_PPC32_F0 + (num - DWARF_PPC32_F0);
|
||||
if (num >= DWARF_PPC32_V0 && num <= DWARF_PPC32_V31)
|
||||
return REGNO_PPC32_V0 + (num - DWARF_PPC32_V0);
|
||||
return LAST_REGISTER + 1;
|
||||
}
|
||||
|
||||
bool validRegister(int num) const {
|
||||
return num >= 0 && num <= LAST_RESTORE_REG;
|
||||
}
|
||||
|
||||
uint64_t getRegister(int num) const {
|
||||
assert(validRegister(num));
|
||||
return reg[num];
|
||||
}
|
||||
|
||||
void setRegister(int num, uint64_t value) {
|
||||
assert(validRegister(num));
|
||||
reg[num] = value;
|
||||
}
|
||||
|
||||
uint64_t getIP() const { return reg[REGNO_PPC32_SRR0]; }
|
||||
|
||||
void setIP(uint64_t value) { reg[REGNO_PPC32_SRR0] = value; }
|
||||
|
||||
uint64_t getSP() const { return reg[REGNO_PPC32_R1]; }
|
||||
|
||||
void setSP(uint64_t value) { reg[REGNO_PPC32_R1] = value; }
|
||||
|
||||
bool validFloatVectorRegister(int num) const {
|
||||
return (num >= REGNO_PPC32_F0 && num <= REGNO_PPC32_F31) ||
|
||||
(num >= REGNO_PPC32_V0 && num <= REGNO_PPC32_V31);
|
||||
}
|
||||
|
||||
void copyFloatVectorRegister(int num, uint64_t addr_) {
|
||||
const void *addr = reinterpret_cast<const void *>(addr_);
|
||||
if (num >= REGNO_PPC32_F0 && num <= REGNO_PPC32_F31)
|
||||
memcpy(fpreg + (num - REGNO_PPC32_F0), addr, sizeof(fpreg[0]));
|
||||
else
|
||||
memcpy(vecreg + (num - REGNO_PPC32_V0), addr, sizeof(vecreg[0]));
|
||||
}
|
||||
|
||||
__dso_hidden void jumpto() const __dead;
|
||||
|
||||
private:
|
||||
struct vecreg_t {
|
||||
uint64_t low, high;
|
||||
};
|
||||
uint32_t reg[REGNO_PPC32_SRR0 + 1];
|
||||
uint64_t fpreg[32];
|
||||
vecreg_t vecreg[64];
|
||||
};
|
||||
|
||||
} // namespace _Unwind
|
||||
|
||||
#endif // __REGISTERS_HPP__
|
142
sys/lib/libunwind/UnwindCursor.hpp
Normal file
142
sys/lib/libunwind/UnwindCursor.hpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
//===------------------------- UnwindCursor.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.
|
||||
//
|
||||
//
|
||||
// C++ interface to lower levels of libuwind
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __UNWINDCURSOR_HPP__
|
||||
#define __UNWINDCURSOR_HPP__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#if !defined(__minix)
|
||||
#include <pthread.h>
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
#include "AddressSpace.hpp"
|
||||
#include "DwarfInstructions.hpp"
|
||||
#include "Registers.hpp"
|
||||
|
||||
namespace _Unwind {
|
||||
|
||||
template <typename A, typename R> class UnwindCursor {
|
||||
public:
|
||||
UnwindCursor(R ®s, A &as)
|
||||
: fRegisters(regs), fAddressSpace(as), fUnwindInfoMissing(false),
|
||||
fIsSignalFrame(false) {
|
||||
memset(&fInfo, 0, sizeof(fInfo));
|
||||
}
|
||||
|
||||
uint64_t getIP() const { return fRegisters.getIP(); }
|
||||
|
||||
void setIP(uint64_t value) { return fRegisters.setIP(value); }
|
||||
|
||||
uint64_t getSP() const { return fRegisters.getSP(); }
|
||||
|
||||
void setSP(uint64_t value) { return fRegisters.setSP(value); }
|
||||
|
||||
bool validReg(int regNum) { return fRegisters.validRegister(regNum); }
|
||||
|
||||
uint64_t getReg(int regNum) { return fRegisters.getRegister(regNum); }
|
||||
|
||||
void setReg(int regNum, uint64_t value) {
|
||||
fRegisters.setRegister(regNum, value);
|
||||
}
|
||||
|
||||
step_result step() {
|
||||
// Bottom of stack is defined as having no more unwind info.
|
||||
if (fUnwindInfoMissing)
|
||||
return UNW_STEP_END;
|
||||
|
||||
// Apply unwinding to register set.
|
||||
switch (this->stepWithDwarfFDE()) {
|
||||
case UNW_STEP_FAILED:
|
||||
return UNW_STEP_FAILED;
|
||||
case UNW_STEP_END:
|
||||
return UNW_STEP_END;
|
||||
case UNW_STEP_SUCCESS:
|
||||
this->setInfoBasedOnIPRegister(true);
|
||||
if (fUnwindInfoMissing)
|
||||
return UNW_STEP_END;
|
||||
return UNW_STEP_SUCCESS;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void getInfo(unw_proc_info_t *info) { *info = fInfo; }
|
||||
|
||||
bool isSignalFrame() { return fIsSignalFrame; }
|
||||
void setInfoBasedOnIPRegister(bool isReturnAddress = false);
|
||||
|
||||
void jumpto() { fRegisters.jumpto(); }
|
||||
|
||||
private:
|
||||
typedef typename A::pint_t pint_t;
|
||||
typedef uint32_t EncodedUnwindInfo;
|
||||
|
||||
bool getInfoFromDwarfSection(pint_t, pint_t, uint32_t, uint32_t);
|
||||
|
||||
step_result stepWithDwarfFDE() {
|
||||
return DwarfInstructions<A, R>::stepWithDwarf(
|
||||
fAddressSpace, this->getIP(), fInfo.unwind_info, fRegisters, &fInfo);
|
||||
}
|
||||
|
||||
unw_proc_info_t fInfo;
|
||||
R fRegisters;
|
||||
A &fAddressSpace;
|
||||
bool fUnwindInfoMissing;
|
||||
bool fIsSignalFrame;
|
||||
};
|
||||
|
||||
template <typename A, typename R>
|
||||
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
||||
pint_t pc = this->getIP();
|
||||
|
||||
// If the last line of a function is a "throw", the compiler sometimes
|
||||
// emits no instructions after the call to __cxa_throw. This means
|
||||
// the return address is actually the start of the next function.
|
||||
// To disambiguate this, back up the PC when we know it is a return
|
||||
// address.
|
||||
if (isReturnAddress)
|
||||
--pc;
|
||||
|
||||
pint_t fdeStart, data_base;
|
||||
if (!fAddressSpace.findFDE(pc, fdeStart, data_base)) {
|
||||
fUnwindInfoMissing = true;
|
||||
return;
|
||||
}
|
||||
fInfo.data_base = data_base;
|
||||
|
||||
typename CFI_Parser<A, R>::FDE_Info fdeInfo;
|
||||
typename CFI_Parser<A, R>::CIE_Info cieInfo;
|
||||
CFI_Parser<A, R>::decodeFDE(fAddressSpace, fdeStart, &fdeInfo, &cieInfo,
|
||||
&fInfo);
|
||||
if (pc < fdeInfo.pcStart || pc > fdeInfo.pcEnd) {
|
||||
fUnwindInfoMissing = true;
|
||||
return;
|
||||
}
|
||||
fInfo.start_ip = fdeInfo.pcStart;
|
||||
|
||||
typename CFI_Parser<A, R>::PrologInfo prolog;
|
||||
if (!CFI_Parser<A, R>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo,
|
||||
pc, &prolog, &fInfo)) {
|
||||
fUnwindInfoMissing = true;
|
||||
return;
|
||||
}
|
||||
// Save off parsed FDE info
|
||||
fInfo.end_ip = fdeInfo.pcEnd;
|
||||
fInfo.lsda = fdeInfo.lsda;
|
||||
fInfo.handler = cieInfo.personality;
|
||||
fInfo.extra_args = prolog.spExtraArgSize;
|
||||
fInfo.unwind_info = fdeInfo.fdeStart;
|
||||
fInfo.unwind_info_size = fdeInfo.fdeLength;
|
||||
}
|
||||
|
||||
}; // namespace _Unwind
|
||||
|
||||
#endif // __UNWINDCURSOR_HPP__
|
237
sys/lib/libunwind/dwarf2.h
Normal file
237
sys/lib/libunwind/dwarf2.h
Normal file
|
@ -0,0 +1,237 @@
|
|||
//===------------------------------- dwarf2.h -----------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/*
|
||||
These constants were taken from version 3 of the DWARF standard,
|
||||
which is Copyright (c) 2005 Free Standards Group, and
|
||||
Copyright (c) 1992, 1993 UNIX International, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __DWARF2__
|
||||
#define __DWARF2__
|
||||
|
||||
// DWARF unwind instructions
|
||||
enum {
|
||||
DW_CFA_nop = 0x0,
|
||||
DW_CFA_set_loc = 0x1,
|
||||
DW_CFA_advance_loc1 = 0x2,
|
||||
DW_CFA_advance_loc2 = 0x3,
|
||||
DW_CFA_advance_loc4 = 0x4,
|
||||
DW_CFA_offset_extended = 0x5,
|
||||
DW_CFA_restore_extended = 0x6,
|
||||
DW_CFA_undefined = 0x7,
|
||||
DW_CFA_same_value = 0x8,
|
||||
DW_CFA_register = 0x9,
|
||||
DW_CFA_remember_state = 0xA,
|
||||
DW_CFA_restore_state = 0xB,
|
||||
DW_CFA_def_cfa = 0xC,
|
||||
DW_CFA_def_cfa_register = 0xD,
|
||||
DW_CFA_def_cfa_offset = 0xE,
|
||||
DW_CFA_def_cfa_expression = 0xF,
|
||||
DW_CFA_expression = 0x10,
|
||||
DW_CFA_offset_extended_sf = 0x11,
|
||||
DW_CFA_def_cfa_sf = 0x12,
|
||||
DW_CFA_def_cfa_offset_sf = 0x13,
|
||||
DW_CFA_val_offset = 0x14,
|
||||
DW_CFA_val_offset_sf = 0x15,
|
||||
DW_CFA_val_expression = 0x16,
|
||||
DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
|
||||
DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
|
||||
DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
|
||||
|
||||
// GNU extensions
|
||||
DW_CFA_GNU_window_save = 0x2D,
|
||||
DW_CFA_GNU_args_size = 0x2E,
|
||||
DW_CFA_GNU_negative_offset_extended = 0x2F
|
||||
};
|
||||
|
||||
|
||||
// FSF exception handling Pointer-Encoding constants
|
||||
// Used in CFI augmentation by GCC
|
||||
enum {
|
||||
DW_EH_PE_ptr = 0x00,
|
||||
DW_EH_PE_uleb128 = 0x01,
|
||||
DW_EH_PE_udata2 = 0x02,
|
||||
DW_EH_PE_udata4 = 0x03,
|
||||
DW_EH_PE_udata8 = 0x04,
|
||||
DW_EH_PE_signed = 0x08,
|
||||
DW_EH_PE_sleb128 = 0x09,
|
||||
DW_EH_PE_sdata2 = 0x0A,
|
||||
DW_EH_PE_sdata4 = 0x0B,
|
||||
DW_EH_PE_sdata8 = 0x0C,
|
||||
DW_EH_PE_absptr = 0x00,
|
||||
DW_EH_PE_pcrel = 0x10,
|
||||
DW_EH_PE_textrel = 0x20,
|
||||
DW_EH_PE_datarel = 0x30,
|
||||
DW_EH_PE_funcrel = 0x40,
|
||||
DW_EH_PE_aligned = 0x50,
|
||||
DW_EH_PE_indirect = 0x80,
|
||||
DW_EH_PE_omit = 0xFF
|
||||
};
|
||||
|
||||
|
||||
// DWARF expressions
|
||||
enum {
|
||||
DW_OP_addr = 0x03, // constant address (size target specific)
|
||||
DW_OP_deref = 0x06,
|
||||
DW_OP_const1u = 0x08, // 1-byte constant
|
||||
DW_OP_const1s = 0x09, // 1-byte constant
|
||||
DW_OP_const2u = 0x0A, // 2-byte constant
|
||||
DW_OP_const2s = 0x0B, // 2-byte constant
|
||||
DW_OP_const4u = 0x0C, // 4-byte constant
|
||||
DW_OP_const4s = 0x0D, // 4-byte constant
|
||||
DW_OP_const8u = 0x0E, // 8-byte constant
|
||||
DW_OP_const8s = 0x0F, // 8-byte constant
|
||||
DW_OP_constu = 0x10, // ULEB128 constant
|
||||
DW_OP_consts = 0x11, // SLEB128 constant
|
||||
DW_OP_dup = 0x12,
|
||||
DW_OP_drop = 0x13,
|
||||
DW_OP_over = 0x14,
|
||||
DW_OP_pick = 0x15, // 1-byte stack index
|
||||
DW_OP_swap = 0x16,
|
||||
DW_OP_rot = 0x17,
|
||||
DW_OP_xderef = 0x18,
|
||||
DW_OP_abs = 0x19,
|
||||
DW_OP_and = 0x1A,
|
||||
DW_OP_div = 0x1B,
|
||||
DW_OP_minus = 0x1C,
|
||||
DW_OP_mod = 0x1D,
|
||||
DW_OP_mul = 0x1E,
|
||||
DW_OP_neg = 0x1F,
|
||||
DW_OP_not = 0x20,
|
||||
DW_OP_or = 0x21,
|
||||
DW_OP_plus = 0x22,
|
||||
DW_OP_plus_uconst = 0x23, // ULEB128 addend
|
||||
DW_OP_shl = 0x24,
|
||||
DW_OP_shr = 0x25,
|
||||
DW_OP_shra = 0x26,
|
||||
DW_OP_xor = 0x27,
|
||||
DW_OP_skip = 0x2F, // signed 2-byte constant
|
||||
DW_OP_bra = 0x28, // signed 2-byte constant
|
||||
DW_OP_eq = 0x29,
|
||||
DW_OP_ge = 0x2A,
|
||||
DW_OP_gt = 0x2B,
|
||||
DW_OP_le = 0x2C,
|
||||
DW_OP_lt = 0x2D,
|
||||
DW_OP_ne = 0x2E,
|
||||
DW_OP_lit0 = 0x30, // Literal 0
|
||||
DW_OP_lit1 = 0x31, // Literal 1
|
||||
DW_OP_lit2 = 0x32, // Literal 2
|
||||
DW_OP_lit3 = 0x33, // Literal 3
|
||||
DW_OP_lit4 = 0x34, // Literal 4
|
||||
DW_OP_lit5 = 0x35, // Literal 5
|
||||
DW_OP_lit6 = 0x36, // Literal 6
|
||||
DW_OP_lit7 = 0x37, // Literal 7
|
||||
DW_OP_lit8 = 0x38, // Literal 8
|
||||
DW_OP_lit9 = 0x39, // Literal 9
|
||||
DW_OP_lit10 = 0x3A, // Literal 10
|
||||
DW_OP_lit11 = 0x3B, // Literal 11
|
||||
DW_OP_lit12 = 0x3C, // Literal 12
|
||||
DW_OP_lit13 = 0x3D, // Literal 13
|
||||
DW_OP_lit14 = 0x3E, // Literal 14
|
||||
DW_OP_lit15 = 0x3F, // Literal 15
|
||||
DW_OP_lit16 = 0x40, // Literal 16
|
||||
DW_OP_lit17 = 0x41, // Literal 17
|
||||
DW_OP_lit18 = 0x42, // Literal 18
|
||||
DW_OP_lit19 = 0x43, // Literal 19
|
||||
DW_OP_lit20 = 0x44, // Literal 20
|
||||
DW_OP_lit21 = 0x45, // Literal 21
|
||||
DW_OP_lit22 = 0x46, // Literal 22
|
||||
DW_OP_lit23 = 0x47, // Literal 23
|
||||
DW_OP_lit24 = 0x48, // Literal 24
|
||||
DW_OP_lit25 = 0x49, // Literal 25
|
||||
DW_OP_lit26 = 0x4A, // Literal 26
|
||||
DW_OP_lit27 = 0x4B, // Literal 27
|
||||
DW_OP_lit28 = 0x4C, // Literal 28
|
||||
DW_OP_lit29 = 0x4D, // Literal 29
|
||||
DW_OP_lit30 = 0x4E, // Literal 30
|
||||
DW_OP_lit31 = 0x4F, // Literal 31
|
||||
DW_OP_reg0 = 0x50, // Contents of reg0
|
||||
DW_OP_reg1 = 0x51, // Contents of reg1
|
||||
DW_OP_reg2 = 0x52, // Contents of reg2
|
||||
DW_OP_reg3 = 0x53, // Contents of reg3
|
||||
DW_OP_reg4 = 0x54, // Contents of reg4
|
||||
DW_OP_reg5 = 0x55, // Contents of reg5
|
||||
DW_OP_reg6 = 0x56, // Contents of reg6
|
||||
DW_OP_reg7 = 0x57, // Contents of reg7
|
||||
DW_OP_reg8 = 0x58, // Contents of reg8
|
||||
DW_OP_reg9 = 0x59, // Contents of reg9
|
||||
DW_OP_reg10 = 0x5A, // Contents of reg10
|
||||
DW_OP_reg11 = 0x5B, // Contents of reg11
|
||||
DW_OP_reg12 = 0x5C, // Contents of reg12
|
||||
DW_OP_reg13 = 0x5D, // Contents of reg13
|
||||
DW_OP_reg14 = 0x5E, // Contents of reg14
|
||||
DW_OP_reg15 = 0x5F, // Contents of reg15
|
||||
DW_OP_reg16 = 0x60, // Contents of reg16
|
||||
DW_OP_reg17 = 0x61, // Contents of reg17
|
||||
DW_OP_reg18 = 0x62, // Contents of reg18
|
||||
DW_OP_reg19 = 0x63, // Contents of reg19
|
||||
DW_OP_reg20 = 0x64, // Contents of reg20
|
||||
DW_OP_reg21 = 0x65, // Contents of reg21
|
||||
DW_OP_reg22 = 0x66, // Contents of reg22
|
||||
DW_OP_reg23 = 0x67, // Contents of reg23
|
||||
DW_OP_reg24 = 0x68, // Contents of reg24
|
||||
DW_OP_reg25 = 0x69, // Contents of reg25
|
||||
DW_OP_reg26 = 0x6A, // Contents of reg26
|
||||
DW_OP_reg27 = 0x6B, // Contents of reg27
|
||||
DW_OP_reg28 = 0x6C, // Contents of reg28
|
||||
DW_OP_reg29 = 0x6D, // Contents of reg29
|
||||
DW_OP_reg30 = 0x6E, // Contents of reg30
|
||||
DW_OP_reg31 = 0x6F, // Contents of reg31
|
||||
DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
|
||||
DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
|
||||
DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
|
||||
DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
|
||||
DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
|
||||
DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
|
||||
DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
|
||||
DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
|
||||
DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
|
||||
DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
|
||||
DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
|
||||
DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
|
||||
DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
|
||||
DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
|
||||
DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
|
||||
DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
|
||||
DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
|
||||
DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
|
||||
DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
|
||||
DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
|
||||
DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
|
||||
DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
|
||||
DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
|
||||
DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
|
||||
DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
|
||||
DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
|
||||
DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
|
||||
DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
|
||||
DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
|
||||
DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
|
||||
DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
|
||||
DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
|
||||
DW_OP_regx = 0x90, // ULEB128 register
|
||||
DW_OP_fbreg = 0x91, // SLEB128 offset
|
||||
DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
|
||||
DW_OP_piece = 0x93, // ULEB128 size of piece addressed
|
||||
DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
|
||||
DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
|
||||
DW_OP_nop = 0x96,
|
||||
DW_OP_push_object_addres = 0x97,
|
||||
DW_OP_call2 = 0x98, // 2-byte offset of DIE
|
||||
DW_OP_call4 = 0x99, // 4-byte offset of DIE
|
||||
DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
|
||||
DW_OP_lo_user = 0xE0,
|
||||
DW_OP_APPLE_uninit = 0xF0,
|
||||
DW_OP_hi_user = 0xFF
|
||||
};
|
||||
|
||||
|
||||
#endif
|
377
sys/lib/libunwind/libunwind.cxx
Normal file
377
sys/lib/libunwind/libunwind.cxx
Normal file
|
@ -0,0 +1,377 @@
|
|||
//===--------------------------- libuwind.cpp -----------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// Implements C++ ABI Exception Handling Level 1 as documented at:
|
||||
// http://mentorembedded.github.io/cxx-abi/abi-eh.html
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <unwind.h>
|
||||
|
||||
#include "UnwindCursor.hpp"
|
||||
|
||||
using namespace _Unwind;
|
||||
|
||||
#if __i386__
|
||||
typedef Registers_x86 ThisUnwindRegisters;
|
||||
#elif __x86_64__
|
||||
typedef Registers_x86_64 ThisUnwindRegisters;
|
||||
#elif __powerpc__
|
||||
typedef Registers_ppc32 ThisUnwindRegisters;
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
typedef CFI_Parser<LocalAddressSpace, ThisUnwindRegisters> MyCFIParser;
|
||||
|
||||
// Internal object representing the address space of this process.
|
||||
static LocalAddressSpace sThisAddressSpace(MyCFIParser::findPCRange);
|
||||
|
||||
typedef UnwindCursor<LocalAddressSpace, ThisUnwindRegisters> ThisUnwindCursor;
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase1(ThisUnwindCursor &cursor,
|
||||
struct _Unwind_Exception *exc) {
|
||||
cursor.setInfoBasedOnIPRegister();
|
||||
|
||||
// Walk frames looking for a place to stop.
|
||||
for (;;) {
|
||||
// Get next frame.
|
||||
// First frame is _Unwind_RaiseException and skipped.
|
||||
switch (cursor.step()) {
|
||||
case UNW_STEP_END:
|
||||
return _URC_END_OF_STACK;
|
||||
case UNW_STEP_FAILED:
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
case UNW_STEP_SUCCESS:
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if there is a personality routine for this frame.
|
||||
unw_proc_info_t frameInfo;
|
||||
cursor.getInfo(&frameInfo);
|
||||
if (frameInfo.end_ip == 0)
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
|
||||
if (frameInfo.handler == 0)
|
||||
continue; // No personality routine, so try next frame.
|
||||
|
||||
__personality_routine p = (__personality_routine)(frameInfo.handler);
|
||||
_Unwind_Reason_Code result = (*p)(1, _UA_SEARCH_PHASE, exc->exception_class,
|
||||
exc, (struct _Unwind_Context *)(&cursor));
|
||||
|
||||
switch (result) {
|
||||
case _URC_HANDLER_FOUND:
|
||||
// This is either a catch clause or a local variable
|
||||
// with destructor.
|
||||
// Stop search and remember the frame for phase 2.
|
||||
exc->private_2 = cursor.getSP();
|
||||
return _URC_NO_REASON;
|
||||
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
// Continue unwinding
|
||||
break;
|
||||
|
||||
default:
|
||||
// Bad personality routine.
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase2(ThisUnwindCursor &cursor,
|
||||
struct _Unwind_Exception *exc) {
|
||||
cursor.setInfoBasedOnIPRegister();
|
||||
|
||||
// Walk frames until the frame selected in phase 1 is reached.
|
||||
for (;;) {
|
||||
// Get next frame.
|
||||
// First frame is _Unwind_RaiseException and skipped.
|
||||
switch (cursor.step()) {
|
||||
case UNW_STEP_END:
|
||||
return _URC_END_OF_STACK;
|
||||
case UNW_STEP_FAILED:
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
case UNW_STEP_SUCCESS:
|
||||
break;
|
||||
}
|
||||
|
||||
unw_proc_info_t frameInfo;
|
||||
cursor.getInfo(&frameInfo);
|
||||
if (frameInfo.end_ip == 0)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
|
||||
if (frameInfo.handler == 0)
|
||||
continue; // No personality routine, continue.
|
||||
|
||||
uintptr_t sp = cursor.getSP();
|
||||
|
||||
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||
// If this frame was selected in phase 1,
|
||||
// inform the personality routine.
|
||||
if (sp == exc->private_2)
|
||||
action = (_Unwind_Action)(action | _UA_HANDLER_FRAME);
|
||||
__personality_routine p = (__personality_routine)(frameInfo.handler);
|
||||
_Unwind_Reason_Code result = (*p)(1, action, exc->exception_class, exc,
|
||||
(struct _Unwind_Context *)(&cursor));
|
||||
switch (result) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
// Continue unwinding unless the selected frame passed.
|
||||
if (sp == exc->private_2)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
// Transfer control to landing pad.
|
||||
cursor.jumpto();
|
||||
default:
|
||||
// Bad personality routine.
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase2_forced(ThisUnwindCursor &cursor,
|
||||
struct _Unwind_Exception *exc,
|
||||
_Unwind_Stop_Fn stop,
|
||||
void *stop_arg) {
|
||||
_Unwind_Action action;
|
||||
cursor.setInfoBasedOnIPRegister();
|
||||
|
||||
// Walk frames until the frame selected in phase 1 is reached.
|
||||
for (;;) {
|
||||
// Get next frame.
|
||||
// First frame is _Unwind_RaiseException and skipped.
|
||||
switch (cursor.step()) {
|
||||
case UNW_STEP_END:
|
||||
case UNW_STEP_FAILED:
|
||||
// End of stack or error condition.
|
||||
// Call the stop function one last time.
|
||||
action = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE |
|
||||
_UA_END_OF_STACK);
|
||||
(*stop)(1, action, exc->exception_class, exc,
|
||||
(struct _Unwind_Context *)(&cursor), stop_arg);
|
||||
|
||||
// Didn't stop at the expected frame, so return error.
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
|
||||
case UNW_STEP_SUCCESS:
|
||||
break;
|
||||
}
|
||||
|
||||
unw_proc_info_t frameInfo;
|
||||
cursor.getInfo(&frameInfo);
|
||||
if (frameInfo.end_ip == 0)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
|
||||
// Call stop function for each frame
|
||||
action = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
|
||||
_Unwind_Reason_Code result =
|
||||
(*stop)(1, action, exc->exception_class, exc,
|
||||
(struct _Unwind_Context *)(&cursor), stop_arg);
|
||||
if (result != _URC_NO_REASON)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
|
||||
if (frameInfo.handler == 0)
|
||||
continue; // No personality routine, continue.
|
||||
|
||||
__personality_routine p = (__personality_routine)(frameInfo.handler);
|
||||
result = (*p)(1, action, exc->exception_class, exc,
|
||||
(struct _Unwind_Context *)(&cursor));
|
||||
|
||||
switch (result) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
// Destructors called, continue.
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
// Transfer control to landing pad.
|
||||
cursor.jumpto();
|
||||
default:
|
||||
// Bad personality routine.
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *exc) {
|
||||
ThisUnwindRegisters registers;
|
||||
ThisUnwindCursor cursor1(registers, sThisAddressSpace);
|
||||
ThisUnwindCursor cursor2(registers, sThisAddressSpace);
|
||||
|
||||
// Mark this as a non-forced unwind for _Unwind_Resume().
|
||||
exc->private_1 = 0;
|
||||
exc->private_2 = 0;
|
||||
|
||||
// Phase 1: searching.
|
||||
_Unwind_Reason_Code phase1 = unwind_phase1(cursor1, exc);
|
||||
if (phase1 != _URC_NO_REASON)
|
||||
return phase1;
|
||||
|
||||
// Phase 2: cleaning up.
|
||||
return unwind_phase2(cursor2, exc);
|
||||
}
|
||||
|
||||
_Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *exc,
|
||||
_Unwind_Stop_Fn stop, void *stop_arg) {
|
||||
ThisUnwindRegisters registers;
|
||||
ThisUnwindCursor cursor(registers, sThisAddressSpace);
|
||||
|
||||
// Mark this as forced unwind for _Unwind_Resume().
|
||||
exc->private_1 = (uintptr_t)stop;
|
||||
exc->private_2 = (uintptr_t)stop_arg;
|
||||
|
||||
return unwind_phase2_forced(cursor, exc, stop, stop_arg);
|
||||
}
|
||||
|
||||
void _Unwind_Resume(struct _Unwind_Exception *exc) {
|
||||
ThisUnwindRegisters registers;
|
||||
ThisUnwindCursor cursor(registers, sThisAddressSpace);
|
||||
|
||||
if (exc->private_1 != 0)
|
||||
unwind_phase2_forced(cursor, exc, (_Unwind_Stop_Fn)exc->private_1,
|
||||
(void *)exc->private_2);
|
||||
else
|
||||
unwind_phase2(cursor, exc);
|
||||
abort();
|
||||
}
|
||||
|
||||
_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exc) {
|
||||
// This is a re-throw, if this is a non-forced unwind
|
||||
// and the stopping place was found.
|
||||
// In that case, call _Unwind_RaiseException() as if
|
||||
// it was a new exception.
|
||||
|
||||
if (exc->private_1 != 0)
|
||||
_Unwind_Resume(exc);
|
||||
|
||||
// This can return if there is no catch clause.
|
||||
// In that case, __cxa_rethrow is expected to call std::terminate().
|
||||
return _Unwind_RaiseException(exc);
|
||||
}
|
||||
|
||||
void _Unwind_DeleteException(struct _Unwind_Exception *exc) {
|
||||
if (exc->exception_cleanup != NULL)
|
||||
(*exc->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
|
||||
}
|
||||
|
||||
uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
return cursor->getReg(index);
|
||||
}
|
||||
|
||||
void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
uintptr_t new_value) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
cursor->setReg(index, new_value);
|
||||
}
|
||||
|
||||
uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
return cursor->getIP();
|
||||
}
|
||||
|
||||
void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t new_value) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
cursor->setIP(new_value);
|
||||
unw_proc_info_t info;
|
||||
cursor->getInfo(&info);
|
||||
uint64_t orgArgSize = info.extra_args;
|
||||
uint64_t orgFuncStart = info.start_ip;
|
||||
cursor->setInfoBasedOnIPRegister(false);
|
||||
// Adjust REG_SP if there was a DW_CFA_GNU_args_size.
|
||||
if (orgFuncStart == info.start_ip && orgArgSize != 0)
|
||||
cursor->setSP(cursor->getSP() + orgArgSize);
|
||||
}
|
||||
|
||||
uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
unw_proc_info_t frameInfo;
|
||||
cursor->getInfo(&frameInfo);
|
||||
return frameInfo.end_ip ? frameInfo.start_ip : 0;
|
||||
}
|
||||
|
||||
uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
unw_proc_info_t frameInfo;
|
||||
cursor->getInfo(&frameInfo);
|
||||
return frameInfo.end_ip ? frameInfo.lsda : 0;
|
||||
}
|
||||
|
||||
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||
ThisUnwindRegisters registers;
|
||||
ThisUnwindCursor cursor(registers, sThisAddressSpace);
|
||||
cursor.setInfoBasedOnIPRegister();
|
||||
|
||||
// Walk each frame.
|
||||
while (true) {
|
||||
|
||||
// Ask libuwind to get next frame (skip over first frame which is
|
||||
// _Unwind_Backtrace()).
|
||||
if (cursor.step() != UNW_STEP_SUCCESS)
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
// Call trace function with this frame.
|
||||
_Unwind_Reason_Code result =
|
||||
(*callback)((struct _Unwind_Context *)(&cursor), ref);
|
||||
if (result != _URC_NO_REASON)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
return cursor->getSP();
|
||||
}
|
||||
|
||||
void *_Unwind_FindEnclosingFunction(void *pc) {
|
||||
ThisUnwindRegisters registers;
|
||||
ThisUnwindCursor cursor(registers, sThisAddressSpace);
|
||||
|
||||
unw_proc_info_t info;
|
||||
cursor.setIP((uintptr_t)pc);
|
||||
cursor.setInfoBasedOnIPRegister();
|
||||
|
||||
cursor.getInfo(&info);
|
||||
return info.end_ip ? (void *)info.start_ip : NULL;
|
||||
}
|
||||
|
||||
uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) {
|
||||
ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
|
||||
unw_proc_info_t frameInfo;
|
||||
cursor->getInfo(&frameInfo);
|
||||
return frameInfo.data_base;
|
||||
}
|
||||
|
||||
uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) { return 0; }
|
||||
|
||||
void __register_frame(const void *fde) {
|
||||
MyCFIParser::pint_t pcStart, pcEnd;
|
||||
|
||||
MyCFIParser::findPCRange(sThisAddressSpace, (uintptr_t)fde, pcStart, pcEnd);
|
||||
if (pcEnd == 0)
|
||||
return; // Bad FDE.
|
||||
|
||||
sThisAddressSpace.addFDE(pcStart, pcEnd, (uintptr_t)fde);
|
||||
}
|
||||
|
||||
void __register_frame_info(const void *ehframe, void *storage) {
|
||||
sThisAddressSpace.setLazyReload();
|
||||
}
|
||||
|
||||
void __deregister_frame(const void *fde) {
|
||||
MyCFIParser::pint_t pcStart, pcEnd;
|
||||
|
||||
MyCFIParser::findPCRange(sThisAddressSpace, (uintptr_t)fde, pcStart, pcEnd);
|
||||
if (pcEnd == 0)
|
||||
return; // Bad FDE.
|
||||
|
||||
sThisAddressSpace.removeFDE(pcStart, pcEnd, (uintptr_t)fde);
|
||||
}
|
||||
|
||||
void *__deregister_frame_info(const void *ehFrameStart) {
|
||||
sThisAddressSpace.removeDSO((LocalAddressSpace::pint_t)ehFrameStart);
|
||||
return NULL;
|
||||
}
|
89
sys/lib/libunwind/unwind.h
Normal file
89
sys/lib/libunwind/unwind.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
//===------------------------------- unwind.h -----------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// C++ ABI Level 1 ABI documented at:
|
||||
// http://mentorembedded.github.io/cxx-abi/abi-eh.html
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _UNWIND_H
|
||||
#define _UNWIND_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum {
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
_URC_NORMAL_STOP = 4,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8
|
||||
} _Unwind_Reason_Code;
|
||||
|
||||
typedef enum {
|
||||
_UA_SEARCH_PHASE = 1,
|
||||
_UA_CLEANUP_PHASE = 2,
|
||||
_UA_HANDLER_FRAME = 4,
|
||||
_UA_FORCE_UNWIND = 8,
|
||||
_UA_END_OF_STACK = 16 /* GCC extension */
|
||||
} _Unwind_Action;
|
||||
|
||||
struct _Unwind_Context;
|
||||
|
||||
struct _Unwind_Exception {
|
||||
uint64_t exception_class;
|
||||
void (*exception_cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception *);
|
||||
uintptr_t private_1;
|
||||
uintptr_t private_2;
|
||||
} __attribute__((__aligned__));
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int, _Unwind_Action, uint64_t,
|
||||
struct _Unwind_Exception *,
|
||||
struct _Unwind_Context *,
|
||||
void *);
|
||||
|
||||
typedef _Unwind_Reason_Code (*__personality_routine)(int, _Unwind_Action,
|
||||
uint64_t,
|
||||
struct _Unwind_Exception *,
|
||||
struct _Unwind_Context *);
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *);
|
||||
void _Unwind_Resume(struct _Unwind_Exception *) __dead;
|
||||
_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *);
|
||||
_Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *,
|
||||
_Unwind_Stop_Fn, void *);
|
||||
void _Unwind_DeleteException(struct _Unwind_Exception *);
|
||||
uintptr_t _Unwind_GetGR(struct _Unwind_Context *, int);
|
||||
void _Unwind_SetGR(struct _Unwind_Context *, int, uintptr_t);
|
||||
uintptr_t _Unwind_GetIP(struct _Unwind_Context *);
|
||||
uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
|
||||
void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t);
|
||||
uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *);
|
||||
uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *);
|
||||
uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *);
|
||||
uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *);
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
|
||||
void *);
|
||||
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
|
||||
void *_Unwind_FindEnclosingFunction(void *);
|
||||
|
||||
void __register_frame(const void *);
|
||||
void __register_frame_info(const void *, void *);
|
||||
void __deregister_frame(const void *);
|
||||
void *__deregister_frame_info(const void *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif // _UNWIND_H
|
212
sys/lib/libunwind/unwind_registers.S
Normal file
212
sys/lib/libunwind/unwind_registers.S
Normal file
|
@ -0,0 +1,212 @@
|
|||
//===------------------------- unwind_registers.S -------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include <machine/asm.h>
|
||||
|
||||
#ifdef __i386__
|
||||
.hidden _ZN7_Unwind13Registers_x86C1Ev
|
||||
ENTRY(_ZN7_Unwind13Registers_x86C1Ev)
|
||||
pushl %eax
|
||||
movl 8(%esp), %eax /* Load this */
|
||||
/* Save all registers except EAX, EIP and ESP */
|
||||
/* Skip ECX */
|
||||
/* Skip EDX */
|
||||
movl %ebx, 12(%eax)
|
||||
movl %ebp, 20(%eax)
|
||||
movl %esi, 24(%eax)
|
||||
movl %edi, 28(%eax)
|
||||
|
||||
leal 8(%esp), %edx /* Compute ESP from the call site */
|
||||
movl %edx, 16(%eax) /* ...and store it as ESP */
|
||||
movl 4(%esp), %edx /* Load return address */
|
||||
movl %edx, 32(%eax) /* ...and store it as EIP */
|
||||
popl %edx /* Take old EAX from stack */
|
||||
movl %edx, 0(%eax) /* ...and store it */ // XXX skip
|
||||
ret
|
||||
|
||||
.hidden _ZNK7_Unwind13Registers_x866jumptoEv
|
||||
ENTRY(_ZNK7_Unwind13Registers_x866jumptoEv)
|
||||
movl 4(%esp), %eax /* Load this */
|
||||
movl 16(%eax), %edx /* Load new stack pointer */
|
||||
subl $4, %edx /* Reserve space on new stack for EIP */
|
||||
movl 32(%eax), %ebx /* Load new EIP */
|
||||
movl %ebx, 0(%edx) /* ...and save it on the new stack */
|
||||
pushl %edx /* Save new stack pointer on old stack */
|
||||
/* New stack is prepared, now restore all registers except ESP */
|
||||
/* EAX is the index register and must be restored last */
|
||||
movl 4(%eax), %ecx
|
||||
movl 8(%eax), %edx
|
||||
movl 12(%eax), %ebx
|
||||
movl 20(%eax), %ebp
|
||||
/* 16 is ESP */
|
||||
movl 24(%eax), %esi
|
||||
movl 28(%eax), %edi
|
||||
movl 0(%eax), %eax
|
||||
/* Now load new stack pointer pushed on the old stack earlier */
|
||||
popl %esp
|
||||
/* Return address is already on the new stack. */
|
||||
ret
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64
|
||||
.hidden _ZN7_Unwind16Registers_x86_64C1Ev
|
||||
ENTRY(_ZN7_Unwind16Registers_x86_64C1Ev)
|
||||
/* RDI == this */
|
||||
/* Skip RAX */
|
||||
/* Skip RDX */
|
||||
/* Skip RCX */
|
||||
movq %rbx, 24(%rdi)
|
||||
/* Skip RSI */
|
||||
/* Skip RDI */
|
||||
movq %rbp, 48(%rdi)
|
||||
leaq 8(%rsp), %rax
|
||||
movq %rax, 56(%rdi)
|
||||
/* Skip R8 */
|
||||
/* Skip R9 */
|
||||
/* Skip R10 */
|
||||
/* Skip R11 */
|
||||
movq %r12, 96(%rdi)
|
||||
movq %r13, 104(%rdi)
|
||||
movq %r14, 112(%rdi)
|
||||
movq %r15, 120(%rdi)
|
||||
movq (%rsp), %rax
|
||||
movq %rax, 128(%rdi)
|
||||
ret
|
||||
|
||||
.hidden _ZNK7_Unwind16Registers_x86_646jumptoEv
|
||||
ENTRY(_ZNK7_Unwind16Registers_x86_646jumptoEv)
|
||||
/* RDI == this */
|
||||
movq 56(%rdi), %rax
|
||||
subq $8, %rax /* Reserve space on new stack for RIP */
|
||||
movq 128(%rdi), %rbx /* Load new RIP */
|
||||
movq %rbx, 0(%rax) /* ...and save it on the new stack */
|
||||
pushq %rax /* Save new stack pointer on old stack */
|
||||
/* New stack is prepared, now restore all registers */
|
||||
movq 0(%rdi), %rax
|
||||
movq 8(%rdi), %rdx
|
||||
movq 16(%rdi), %rcx
|
||||
movq 24(%rdi), %rbx
|
||||
movq 32(%rdi), %rsi
|
||||
/* RDI restored later as it is still used as index register */
|
||||
movq 48(%rdi), %rbp
|
||||
/* RSP is restored later */
|
||||
movq 64(%rdi), %r8
|
||||
movq 72(%rdi), %r9
|
||||
movq 80(%rdi), %r10
|
||||
movq 88(%rdi), %r11
|
||||
movq 96(%rdi), %r12
|
||||
movq 104(%rdi), %r13
|
||||
movq 112(%rdi), %r14
|
||||
movq 120(%rdi), %r15
|
||||
movq 40(%rdi), %rdi
|
||||
/* Now load new stack pointer pushed on the old stack earlier */
|
||||
popq %rsp
|
||||
/* Return address is already on the new stack. */
|
||||
ret
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
.hidden _ZN7_Unwind15Registers_ppc32C1Ev
|
||||
ENTRY(_ZN7_Unwind15Registers_ppc32C1Ev)
|
||||
stw %r0, 0(%r3)
|
||||
stw %r1, 4(%r3)
|
||||
stw %r2, 8(%r3)
|
||||
stw %r3, 12(%r3)
|
||||
stw %r4, 16(%r3)
|
||||
stw %r5, 20(%r3)
|
||||
stw %r6, 24(%r3)
|
||||
stw %r7, 28(%r3)
|
||||
stw %r8, 32(%r3)
|
||||
stw %r9, 36(%r3)
|
||||
stw %r10, 40(%r3)
|
||||
stw %r11, 44(%r3)
|
||||
stw %r12, 48(%r3)
|
||||
stw %r13, 52(%r3)
|
||||
stw %r14, 56(%r3)
|
||||
stw %r15, 60(%r3)
|
||||
stw %r16, 64(%r3)
|
||||
stw %r17, 68(%r3)
|
||||
stw %r18, 72(%r3)
|
||||
stw %r19, 76(%r3)
|
||||
stw %r20, 80(%r3)
|
||||
stw %r21, 84(%r3)
|
||||
stw %r22, 88(%r3)
|
||||
stw %r23, 92(%r3)
|
||||
stw %r24, 96(%r3)
|
||||
stw %r25,100(%r3)
|
||||
stw %r26,104(%r3)
|
||||
stw %r27,108(%r3)
|
||||
stw %r28,112(%r3)
|
||||
stw %r29,116(%r3)
|
||||
stw %r30,120(%r3)
|
||||
stw %r31,124(%r3)
|
||||
|
||||
mfcr %r0
|
||||
stw %r0, 128(%r3) /* CR */
|
||||
mflr %r0
|
||||
stw %r0, 132(%r3) /* LR */
|
||||
stw %r0, 144(%r3) /* LR */
|
||||
mfctr %r0
|
||||
stw %r0, 136(%r3) /* CTR */
|
||||
mfxer %r0
|
||||
stw %r0, 140(%r3) /* XER */
|
||||
|
||||
blr
|
||||
|
||||
.hidden _ZNK7_Unwind15Registers_ppc326jumptoEv
|
||||
ENTRY(_ZNK7_Unwind15Registers_ppc326jumptoEv)
|
||||
lwz %r2, 8(%r3)
|
||||
/* skip r3 for now */
|
||||
lwz %r4, 16(%r3)
|
||||
lwz %r5, 20(%r3)
|
||||
lwz %r6, 24(%r3)
|
||||
lwz %r7, 28(%r3)
|
||||
lwz %r8, 32(%r3)
|
||||
lwz %r9, 36(%r3)
|
||||
lwz %r10, 40(%r3)
|
||||
lwz %r11, 44(%r3)
|
||||
lwz %r12, 48(%r3)
|
||||
lwz %r13, 52(%r3)
|
||||
lwz %r14, 56(%r3)
|
||||
lwz %r15, 60(%r3)
|
||||
lwz %r16, 64(%r3)
|
||||
lwz %r17, 68(%r3)
|
||||
lwz %r18, 72(%r3)
|
||||
lwz %r19, 76(%r3)
|
||||
lwz %r20, 80(%r3)
|
||||
lwz %r21, 84(%r3)
|
||||
lwz %r22, 88(%r3)
|
||||
lwz %r23, 92(%r3)
|
||||
lwz %r24, 96(%r3)
|
||||
lwz %r25,100(%r3)
|
||||
lwz %r26,104(%r3)
|
||||
lwz %r27,108(%r3)
|
||||
lwz %r28,112(%r3)
|
||||
lwz %r29,116(%r3)
|
||||
lwz %r30,120(%r3)
|
||||
lwz %r31,124(%r3)
|
||||
|
||||
lwz %r0, 128(%r3) /* CR */
|
||||
mtcr %r0
|
||||
lwz %r0, 132(%r3) /* LR */
|
||||
mtlr %r0
|
||||
lwz %r0, 136(%r3) /* CTR */
|
||||
mtctr %r0
|
||||
lwz %r0, 140(%r3) /* XER */
|
||||
mtxer %r0
|
||||
lwz %r0, 144(%r3) /* SRR0 ? */
|
||||
mtctr %r0
|
||||
|
||||
lwz %r0, 0(%r3) /* do r0 now */
|
||||
lwz %r1,4(%r3) /* do sp now */
|
||||
lwz %r3,12(%r3) /* do r3 last */
|
||||
bctr
|
||||
#endif
|
Loading…
Reference in a new issue