Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/lib/libunwind Add a heavily modified version of Apple's ...



details:   https://anonhg.NetBSD.org/src/rev/d88baea7e967
branches:  trunk
changeset: 790475:d88baea7e967
user:      joerg <joerg%NetBSD.org@localhost>
date:      Mon Oct 14 01:14:57 2013 +0000

description:
Add a heavily modified version of Apple's libunwind as released under
MIT license in libc++abi. At the moment, only x86 support is tested.

diffstat:

 sys/lib/libunwind/AddressSpace.hpp      |  471 +++++++++++++++++++++++++
 sys/lib/libunwind/CREDITS.TXT           |   42 ++
 sys/lib/libunwind/DwarfInstructions.hpp |  597 ++++++++++++++++++++++++++++++++
 sys/lib/libunwind/DwarfParser.hpp       |  529 ++++++++++++++++++++++++++++
 sys/lib/libunwind/LICENSE.TXT           |   76 ++++
 sys/lib/libunwind/Makefile.inc          |   10 +
 sys/lib/libunwind/Registers.hpp         |  234 ++++++++++++
 sys/lib/libunwind/UnwindCursor.hpp      |  140 +++++++
 sys/lib/libunwind/dwarf2.h              |  237 ++++++++++++
 sys/lib/libunwind/libunwind.cxx         |  377 ++++++++++++++++++++
 sys/lib/libunwind/unwind.h              |   89 ++++
 sys/lib/libunwind/unwind_registers.S    |  212 +++++++++++
 12 files changed, 3014 insertions(+), 0 deletions(-)

diffs (truncated from 3062 to 300 lines):

diff -r 4f83f5da29b1 -r d88baea7e967 sys/lib/libunwind/AddressSpace.hpp
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/lib/libunwind/AddressSpace.hpp        Mon Oct 14 01:14:57 2013 +0000
@@ -0,0 +1,471 @@
+//===------------------------- 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>
+#include <pthread.h>
+
+#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);



Home | Main Index | Thread Index | Old Index