diff options
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp')
-rw-r--r-- | lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp | 456 |
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__ |