./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
--- /dev/null
+//===------------------------- 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__
--- /dev/null
+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
--- /dev/null
+//===-------------------------- 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__
--- /dev/null
+//===--------------------------- 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__
--- /dev/null
+==============================================================================
+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.
--- /dev/null
+# $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
--- /dev/null
+//===----------------------------- 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__
--- /dev/null
+//===------------------------- 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__
--- /dev/null
+//===------------------------------- 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
--- /dev/null
+//===--------------------------- 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;
+}
--- /dev/null
+//===------------------------------- 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
--- /dev/null
+//===------------------------- 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