Importing sys/libunwind for clang

Change-Id: Ib073b27e3b883837e682414ef7df56c84ca10816
This commit is contained in:
Lionel Sambuc 2013-12-07 19:53:33 +01:00
parent fed2e50bd7
commit 472758f313
13 changed files with 3026 additions and 0 deletions

View file

@ -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

View 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__

View 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

View 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 &registers) {
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 &registers, 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 &registers, 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 &registers,
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 &registers,
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__

View 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__

View 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.

View 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

View 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__

View 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 &regs, 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
View 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

View 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;
}

View 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

View 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