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