]> Zhao Yanbai Git Server - minix.git/commitdiff
Importing sys/libunwind for clang
authorLionel Sambuc <lionel@minix3.org>
Sat, 7 Dec 2013 18:53:33 +0000 (19:53 +0100)
committerLionel Sambuc <lionel@minix3.org>
Mon, 28 Jul 2014 15:06:01 +0000 (17:06 +0200)
Change-Id: Ib073b27e3b883837e682414ef7df56c84ca10816

13 files changed:
distrib/sets/lists/minix/mi
sys/lib/libunwind/AddressSpace.hpp [new file with mode: 0644]
sys/lib/libunwind/CREDITS.TXT [new file with mode: 0644]
sys/lib/libunwind/DwarfInstructions.hpp [new file with mode: 0644]
sys/lib/libunwind/DwarfParser.hpp [new file with mode: 0644]
sys/lib/libunwind/LICENSE.TXT [new file with mode: 0644]
sys/lib/libunwind/Makefile.inc [new file with mode: 0644]
sys/lib/libunwind/Registers.hpp [new file with mode: 0644]
sys/lib/libunwind/UnwindCursor.hpp [new file with mode: 0644]
sys/lib/libunwind/dwarf2.h [new file with mode: 0644]
sys/lib/libunwind/libunwind.cxx [new file with mode: 0644]
sys/lib/libunwind/unwind.h [new file with mode: 0644]
sys/lib/libunwind/unwind_registers.S [new file with mode: 0644]

index 05f87dfb32bab55f9f5965b315396d4281cdd695..470c2bee9cd8309b466bad4405b068ffb45f1570 100644 (file)
 ./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
diff --git a/sys/lib/libunwind/AddressSpace.hpp b/sys/lib/libunwind/AddressSpace.hpp
new file mode 100644 (file)
index 0000000..31b5619
--- /dev/null
@@ -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__
diff --git a/sys/lib/libunwind/CREDITS.TXT b/sys/lib/libunwind/CREDITS.TXT
new file mode 100644 (file)
index 0000000..bd54ba9
--- /dev/null
@@ -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
diff --git a/sys/lib/libunwind/DwarfInstructions.hpp b/sys/lib/libunwind/DwarfInstructions.hpp
new file mode 100644 (file)
index 0000000..37c0a3c
--- /dev/null
@@ -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__
diff --git a/sys/lib/libunwind/DwarfParser.hpp b/sys/lib/libunwind/DwarfParser.hpp
new file mode 100644 (file)
index 0000000..6715020
--- /dev/null
@@ -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__
diff --git a/sys/lib/libunwind/LICENSE.TXT b/sys/lib/libunwind/LICENSE.TXT
new file mode 100644 (file)
index 0000000..b04ba2c
--- /dev/null
@@ -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.
diff --git a/sys/lib/libunwind/Makefile.inc b/sys/lib/libunwind/Makefile.inc
new file mode 100644 (file)
index 0000000..4a59407
--- /dev/null
@@ -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
diff --git a/sys/lib/libunwind/Registers.hpp b/sys/lib/libunwind/Registers.hpp
new file mode 100644 (file)
index 0000000..dc18d07
--- /dev/null
@@ -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__
diff --git a/sys/lib/libunwind/UnwindCursor.hpp b/sys/lib/libunwind/UnwindCursor.hpp
new file mode 100644 (file)
index 0000000..2c09467
--- /dev/null
@@ -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__
diff --git a/sys/lib/libunwind/dwarf2.h b/sys/lib/libunwind/dwarf2.h
new file mode 100644 (file)
index 0000000..0dcd2ca
--- /dev/null
@@ -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
diff --git a/sys/lib/libunwind/libunwind.cxx b/sys/lib/libunwind/libunwind.cxx
new file mode 100644 (file)
index 0000000..30f579e
--- /dev/null
@@ -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;
+}
diff --git a/sys/lib/libunwind/unwind.h b/sys/lib/libunwind/unwind.h
new file mode 100644 (file)
index 0000000..c89b01f
--- /dev/null
@@ -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
diff --git a/sys/lib/libunwind/unwind_registers.S b/sys/lib/libunwind/unwind_registers.S
new file mode 100644 (file)
index 0000000..b87f163
--- /dev/null
@@ -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