summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp')
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp456
1 files changed, 456 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp
new file mode 100644
index 00000000000..5173dc0068e
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp
@@ -0,0 +1,456 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- AddressSpace.hpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __ADDRESSSPACE_HPP__
+#define __ADDRESSSPACE_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+#include <mach-o/dyld_priv.h>
+#endif
+#include <mach/ppc/thread_status.h>
+#include <mach/i386/thread_status.h>
+#include <Availability.h>
+
+#include "FileAbstraction.hpp"
+#include "libunwind.h"
+#include "InternalMacros.h"
+#include "dwarf2.h"
+#include "RemoteProcInfo.hpp"
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+bool _dyld_find_unwind_sections(void* addr, void* info)
+{
+ assert("unwinding with a non-remote process not supported.");
+ return false;
+}
+#endif // SUPPORT_REMOTE_UNWINDING
+
+namespace lldb_private {
+
+///
+/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the same process. It compiles away and making local unwinds very fast.
+///
+class LocalAddressSpace
+{
+public:
+
+ #if __LP64__
+ typedef uint64_t pint_t;
+ typedef int64_t sint_t;
+ #else
+ typedef uint32_t pint_t;
+ typedef int32_t sint_t;
+ #endif
+ int getBytes(pint_t addr, pint_t extent, uint8_t* buf) { memcpy(buf, (void*)addr, extent); return 1; }
+ 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); }
+ double getDouble(pint_t addr) { return *((double*)addr); }
+ v128 getVector(pint_t addr) { return *((v128*)addr); }
+
+ uint8_t get8(pint_t addr, int& err) { return *((uint8_t*)addr); err = 0; }
+ uint16_t get16(pint_t addr, int& err) { return *((uint16_t*)addr); err = 0; }
+ uint32_t get32(pint_t addr, int& err) { return *((uint32_t*)addr); err = 0; }
+ uint64_t get64(pint_t addr, int& err) { return *((uint64_t*)addr); err = 0; }
+ double getDouble(pint_t addr, int& err) { return *((double*)addr); err = 0; }
+ v128 getVector(pint_t addr, int& err) { return *((v128*)addr); err = 0; }
+
+ uintptr_t getP(pint_t addr);
+ uintptr_t getP(pint_t addr, int &err);
+ static uint64_t getULEB128(pint_t& addr, pint_t end);
+ static int64_t getSLEB128(pint_t& addr, pint_t end);
+
+ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+ bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart);
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+ RemoteProcInfo* getRemoteProcInfo () { return NULL; }
+ unw_accessors_t* accessors() { return NULL; }
+ unw_addr_space_t wrap() { return NULL; }
+#endif
+};
+
+LocalAddressSpace sThisAddress;
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr)
+{
+#if __LP64__
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+}
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr, int &err)
+{
+#if __LP64__
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+ err = 0;
+}
+
+/* Read a ULEB128 into a 64-bit word. */
+inline uint64_t
+LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ const uint8_t* pend = (uint8_t*)end;
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ uint64_t b;
+
+ if ( p == pend )
+ ABORT("truncated uleb128 expression");
+
+ b = *p & 0x7f;
+
+ if (bit >= 64 || b << bit >> bit != b) {
+ ABORT("malformed uleb128 expression");
+ }
+ else {
+ result |= b << bit;
+ bit += 7;
+ }
+ } while ( *p++ >= 0x80 );
+ addr = (pint_t)p;
+ return result;
+}
+
+/* Read a SLEB128 into a 64-bit word. */
+inline int64_t
+LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ byte = *p++;
+ result |= ((byte & 0x7f) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ( (byte & 0x40) != 0 )
+ result |= (-1LL) << bit;
+ addr = (pint_t)p;
+ return result;
+}
+
+LocalAddressSpace::pint_t
+LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+ pint_t startAddr = addr;
+ const uint8_t* p = (uint8_t*)addr;
+ pint_t result;
+
+ // 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;
+ default:
+ ABORT("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:
+ ABORT("DW_EH_PE_textrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_datarel:
+ ABORT("DW_EH_PE_datarel pointer encoding not supported");
+ break;
+ case DW_EH_PE_funcrel:
+ ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_aligned:
+ ABORT("DW_EH_PE_aligned pointer encoding not supported");
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ break;
+ }
+
+ if ( encoding & DW_EH_PE_indirect )
+ result = getP(result);
+
+ return result;
+}
+
+
+inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart)
+{
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ dyld_unwind_sections info;
+ if ( _dyld_find_unwind_sections((void*)addr, &info) ) {
+ mh = (pint_t)info.mh;
+ dwarfStart = (pint_t)info.dwarf_section;
+ dwarfLen = (pint_t)info.dwarf_section_length;
+ compactStart = (pint_t)info.compact_unwind_section;
+ return true;
+ }
+#else
+ assert("unwinding with a non-remote process not supported.");
+#endif
+ return false;
+}
+
+
+inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ dl_info dyldInfo;
+ if ( dladdr((void*)addr, &dyldInfo) ) {
+ if ( dyldInfo.dli_sname != NULL ) {
+ strlcpy(buf, dyldInfo.dli_sname, bufLen);
+ *offset = (addr - (pint_t)dyldInfo.dli_saddr);
+ return true;
+ }
+ }
+ return false;
+}
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+///
+/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the another process. The other process can be a different endianness and a different
+/// pointer size and is handled by the P template parameter.
+///
+template <typename P>
+class OtherAddressSpace
+{
+public:
+ OtherAddressSpace (unw_addr_space_t remote_addr_space, void* arg) : fAddrSpace ((unw_addr_space_remote *)remote_addr_space), fArg(arg)
+ {
+ if (fAddrSpace->type != UNW_REMOTE)
+ ABORT("OtherAddressSpace ctor called with non-remote address space.");
+ fRemoteProcInfo = fAddrSpace->ras;
+ }
+
+ typedef typename P::uint_t pint_t;
+ typedef typename P::int_t sint_t;
+
+ int getBytes(pint_t addr, pint_t extent, uint8_t* buf) { return fRemoteProcInfo->getBytes (addr, extent, buf, fArg); }
+ uint8_t get8(pint_t addr) { return fRemoteProcInfo->get8(addr, fArg); }
+ uint16_t get16(pint_t addr) { return fRemoteProcInfo->get16(addr, fArg); }
+ uint32_t get32(pint_t addr) { return fRemoteProcInfo->get32(addr, fArg); }
+ uint64_t get64(pint_t addr) { return fRemoteProcInfo->get64(addr, fArg); }
+ pint_t getP(pint_t addr) { return fRemoteProcInfo->getP(addr, fArg); }
+
+ uint8_t get8(pint_t addr, int& err) { return fRemoteProcInfo->get8(addr, err, fArg); }
+ uint16_t get16(pint_t addr, int& err) { return fRemoteProcInfo->get16(addr, err, fArg); }
+ uint32_t get32(pint_t addr, int& err) { return fRemoteProcInfo->get32(addr, err, fArg); }
+ uint64_t get64(pint_t addr, int& err) { return fRemoteProcInfo->get64(addr, err, fArg); }
+ pint_t getP(pint_t addr, int &err) { return fRemoteProcInfo->getP(addr, err, fArg); }
+
+ uint64_t getULEB128(pint_t& addr, pint_t end) { return fRemoteProcInfo->getULEB128 (addr, end, fArg); }
+ int64_t getSLEB128(pint_t& addr, pint_t end) { return fRemoteProcInfo->getSLEB128 (addr, end, fArg); }
+ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+ double getDouble(pint_t addr);
+ v128 getVector(pint_t addr);
+ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+ bool findFunctionExtent(pint_t addr, unw_word_t* begin, unw_word_t* end);
+ bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& eh_frame_start, pint_t& eh_frame_len, pint_t& compactStart);
+ RemoteProcInfo* getRemoteProcInfo () { return fRemoteProcInfo; }
+ unw_accessors_t* accessors() { return fRemoteProcInfo->getAccessors(); }
+ unw_addr_space_t wrap() { return (unw_addr_space_t) fAddrSpace; }
+private:
+ void* localCopy(pint_t addr);
+ unw_addr_space_remote *fAddrSpace;
+ RemoteProcInfo* fRemoteProcInfo;
+ void* fArg;
+};
+
+template <typename P>
+typename OtherAddressSpace<P>::pint_t OtherAddressSpace<P>::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+ pint_t startAddr = addr;
+ pint_t p = addr;
+ pint_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = fRemoteProcInfo->getP(addr, fArg);
+ p += sizeof(pint_t);
+ addr = p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = fRemoteProcInfo->getULEB128(addr, end, fArg);
+ break;
+ case DW_EH_PE_udata2:
+ result = fRemoteProcInfo->get16(addr, fArg);
+ p += 2;
+ addr = p;
+ break;
+ case DW_EH_PE_udata4:
+ result = fRemoteProcInfo->get32(addr, fArg);
+ p += 4;
+ addr = p;
+ break;
+ case DW_EH_PE_udata8:
+ result = fRemoteProcInfo->get64(addr, fArg);
+ p += 8;
+ addr = p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = fRemoteProcInfo->getSLEB128(addr, end, fArg);
+ break;
+ case DW_EH_PE_sdata2:
+ result = (int16_t)fRemoteProcInfo->get16(addr, fArg);
+ p += 2;
+ addr = p;
+ break;
+ case DW_EH_PE_sdata4:
+ result = (int32_t)fRemoteProcInfo->get32(addr, fArg);
+ p += 4;
+ addr = p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = fRemoteProcInfo->get64(addr, fArg);
+ p += 8;
+ addr = p;
+ break;
+ default:
+ ABORT("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:
+ ABORT("DW_EH_PE_textrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_datarel:
+ ABORT("DW_EH_PE_datarel pointer encoding not supported");
+ break;
+ case DW_EH_PE_funcrel:
+ ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_aligned:
+ ABORT("DW_EH_PE_aligned pointer encoding not supported");
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ break;
+ }
+
+ if ( encoding & DW_EH_PE_indirect )
+ result = fRemoteProcInfo->getP(result, fArg);
+
+ return result;
+}
+
+template <typename P>
+double OtherAddressSpace<P>::getDouble(pint_t addr)
+{
+ return fRemoteProcInfo->getDouble(addr, fArg);
+}
+
+template <typename P>
+v128 OtherAddressSpace<P>::getVector(pint_t addr)
+{
+ return fRemoteProcInfo->getVector(addr, fArg);
+}
+
+template <typename P>
+bool OtherAddressSpace<P>::findUnwindSections(pint_t addr, pint_t& mh, pint_t& eh_frame_start, pint_t& eh_frame_len, pint_t& compactStart)
+{
+ compactStart = 0;
+ uint64_t t_mh, t_text_start, t_text_end, t_eh_frame_start, t_eh_frame_len, t_compact_start;
+ if (fRemoteProcInfo->getImageAddresses (addr, t_mh, t_text_start, t_text_end, t_eh_frame_start, t_eh_frame_len, t_compact_start, fArg))
+ {
+ mh = t_mh;
+ eh_frame_start = t_eh_frame_start;
+ eh_frame_len = t_eh_frame_len;
+ compactStart = t_compact_start;
+ return true;
+ }
+ return false;
+}
+
+template <typename P>
+bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ return fRemoteProcInfo->findFunctionName (addr, buf, bufLen, offset, fArg);
+}
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+
+} // namespace lldb_private
+
+
+
+#endif // __ADDRESSSPACE_HPP__
OpenPOWER on IntegriCloud