summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp')
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp1307
1 files changed, 1307 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp
new file mode 100644
index 00000000000..e940b8b8bf1
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp
@@ -0,0 +1,1307 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- UnwindCursor.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 __UNWINDCURSOR_HPP__
+#define __UNWINDCURSOR_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdarg.h>
+
+#include "libunwind.h"
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfInstructions.hpp"
+
+#include "AssemblyParser.hpp"
+#include "AssemblyInstructions.hpp"
+#include "RemoteProcInfo.hpp"
+#include "ArchDefaultUnwinder.hpp"
+#include "RemoteDebuggerDummyUnwinder.hpp"
+
+#include "CompactUnwinder.hpp"
+#include "InternalMacros.h"
+
+// private keymgr stuff
+#define KEYMGR_GCC3_DW2_OBJ_LIST 302
+extern "C" {
+ extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr);
+ extern void* _keymgr_get_and_lock_processwide_ptr(int key);
+};
+
+// undocumented libgcc "struct object"
+struct libgcc_object
+{
+ void* start;
+ void* unused1;
+ void* unused2;
+ void* fde;
+ unsigned long encoding;
+ void* fde_end;
+ libgcc_object* next;
+};
+
+// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST
+struct libgcc_object_info {
+ struct libgcc_object* seen_objects;
+ struct libgcc_object* unseen_objects;
+ unsigned spare[2];
+};
+
+
+
+
+namespace lldb_private {
+
+#if !FOR_DYLD
+template <typename A>
+class DwarfFDECache
+{
+public:
+ typedef typename A::pint_t pint_t;
+ static pint_t findFDE(pint_t mh, pint_t pc);
+ static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
+ static void removeAllIn(pint_t mh);
+ static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
+private:
+ static void dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide);
+
+ struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; };
+
+ // these fields are all static to avoid needing an initializer
+ // there is only one instance of this class per process
+ static pthread_rwlock_t fgLock;
+ static bool fgRegisteredForDyldUnloads;
+ // can't use std::vector<> here because this code must live in libSystem.dylib (which is below libstdc++.dylib)
+ static entry* fgBuffer;
+ static entry* fgBufferUsed;
+ static entry* fgBufferEnd;
+ static entry fgInitialBuffer[64];
+};
+
+template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBuffer = fgInitialBuffer;
+template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferUsed = fgInitialBuffer;
+template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferEnd = &fgInitialBuffer[64];
+template <typename A> typename DwarfFDECache<A>::entry DwarfFDECache<A>::fgInitialBuffer[64];
+
+template <typename A>
+pthread_rwlock_t DwarfFDECache<A>::fgLock = PTHREAD_RWLOCK_INITIALIZER;
+
+template <typename A>
+bool DwarfFDECache<A>::fgRegisteredForDyldUnloads = false;
+
+
+template <typename A>
+typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc)
+{
+ pint_t result = NULL;
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_rdlock(&fgLock));
+ for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
+ if ( (mh == p->mh) || (mh == 0) ) {
+ if ( (p->ip_start <= pc) && (pc < p->ip_end) ) {
+ result = p->fde;
+ break;
+ }
+ }
+ }
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+ //fprintf(stderr, "DwarfFDECache::findFDE(mh=0x%llX, pc=0x%llX) => 0x%llX\n", (uint64_t)mh, (uint64_t)pc, (uint64_t)result);
+ return result;
+}
+
+template <typename A>
+void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde)
+{
+ //fprintf(stderr, "DwarfFDECache::add(mh=0x%llX, ip_start=0x%llX, ip_end=0x%llX, fde=0x%llX) pthread=%p\n",
+ // (uint64_t)mh, (uint64_t)ip_start, (uint64_t)ip_end, (uint64_t)fde, pthread_self());
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
+ if ( fgBufferUsed >= fgBufferEnd ) {
+ int oldSize = fgBufferEnd - fgBuffer;
+ int newSize = oldSize*4;
+ entry* newBuffer = (entry*)malloc(newSize*sizeof(entry)); // can't use operator new in libSystem.dylib
+ memcpy(newBuffer, fgBuffer, oldSize*sizeof(entry));
+ //fprintf(stderr, "DwarfFDECache::add() growing buffer to %d\n", newSize);
+ if ( fgBuffer != fgInitialBuffer )
+ free(fgBuffer);
+ fgBuffer = newBuffer;
+ fgBufferUsed = &newBuffer[oldSize];
+ fgBufferEnd = &newBuffer[newSize];
+ }
+ fgBufferUsed->mh = mh;
+ fgBufferUsed->ip_start = ip_start;
+ fgBufferUsed->ip_end = ip_end;
+ fgBufferUsed->fde = fde;
+ ++fgBufferUsed;
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ if ( !fgRegisteredForDyldUnloads ) {
+ _dyld_register_func_for_remove_image(&dyldUnloadHook);
+ fgRegisteredForDyldUnloads = true;
+ }
+#endif
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+}
+
+
+
+template <typename A>
+void DwarfFDECache<A>::removeAllIn(pint_t mh)
+{
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
+ entry* d=fgBuffer;
+ for(const entry* s=fgBuffer; s < fgBufferUsed; ++s) {
+ if ( s->mh != mh ) {
+ if ( d != s )
+ *d = *s;
+ ++d;
+ }
+ }
+ fgBufferUsed = d;
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+}
+
+
+template <typename A>
+void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide)
+{
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ removeAllIn((pint_t)mh);
+#endif
+}
+
+template <typename A>
+void DwarfFDECache<A>::iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh))
+{
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
+ for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
+ (*func)(p->ip_start, p->ip_end, p->fde, p->mh);
+ }
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+}
+#endif // !FOR_DYLD
+
+
+
+
+#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
+
+template <typename A>
+class UnwindSectionHeader {
+public:
+ UnwindSectionHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t version() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, version)); }
+ uint32_t commonEncodingsArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); }
+ uint32_t commonEncodingsArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); }
+ uint32_t personalityArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); }
+ uint32_t personalityArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArrayCount)); }
+ uint32_t indexSectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexSectionOffset)); }
+ uint32_t indexCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexCount)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+template <typename A>
+class UnwindSectionIndexArray {
+public:
+ UnwindSectionIndexArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); }
+ uint32_t secondLevelPagesSectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); }
+ uint32_t lsdaIndexArraySectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionRegularPageHeader {
+public:
+ UnwindSectionRegularPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_regular_second_level_page_header, kind)); }
+ uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); }
+ uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionRegularArray {
+public:
+ UnwindSectionRegularArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); }
+ uint32_t encoding(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionCompressedPageHeader {
+public:
+ UnwindSectionCompressedPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_compressed_second_level_page_header, kind)); }
+ uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); }
+ uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); }
+ uint16_t encodingsPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); }
+ uint16_t encodingsCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionCompressedArray {
+public:
+ UnwindSectionCompressedArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
+ uint16_t encodingIndex(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionLsdaArray {
+public:
+ UnwindSectionLsdaArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); }
+ int32_t lsdaOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A, typename R>
+class UnwindCursor
+{
+public:
+ UnwindCursor(unw_context_t* context, A& as);
+ virtual ~UnwindCursor() {}
+ virtual bool validReg(int);
+ virtual uint64_t getReg(int);
+ virtual int getReg(int, uint64_t*);
+ virtual int setReg(int, uint64_t);
+ virtual bool validFloatReg(int);
+ virtual double getFloatReg(int);
+ virtual int getFloatReg(int, double*);
+ virtual int setFloatReg(int, double);
+ virtual int step();
+ virtual void getInfo(unw_proc_info_t*);
+ virtual void jumpto();
+ virtual const char* getRegisterName(int num);
+ virtual bool isSignalFrame();
+ virtual bool getFunctionName(char* buf, size_t bufLen, unw_word_t* offset);
+ virtual void setInfoBasedOnIPRegister(bool isReturnAddress=false);
+
+ void operator delete(void* p, size_t size) {}
+
+protected:
+ typedef typename A::pint_t pint_t;
+ typedef uint32_t EncodedUnwindInfo;
+
+ virtual bool getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart);
+ virtual bool getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE);
+
+ virtual int stepWithDwarfFDE()
+ { return DwarfInstructions<A,R>::stepWithDwarf(fAddressSpace, this->getReg(UNW_REG_IP), fInfo.unwind_info, fRegisters); }
+
+ virtual int stepWithCompactEncoding() { R dummy; return stepWithCompactEncoding(dummy); }
+ int stepWithCompactEncoding(Registers_x86_64&)
+ { return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
+ int stepWithCompactEncoding(Registers_x86&)
+ { return CompactUnwinder_x86<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
+ int stepWithCompactEncoding(Registers_ppc&)
+ { return UNW_EINVAL; }
+
+#if FOR_DYLD
+ #if __ppc__
+ virtual bool mustUseDwarf() const { return true; }
+ #else
+ virtual bool mustUseDwarf() const { return false; }
+ #endif
+#else
+ virtual bool mustUseDwarf() const { R dummy; uint32_t offset; return dwarfWithOffset(dummy, offset); }
+#endif
+
+ virtual bool dwarfWithOffset(uint32_t& offset) const { R dummy; return dwarfWithOffset(dummy, offset); }
+ virtual bool dwarfWithOffset(Registers_x86_64&, uint32_t& offset) const {
+ if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
+ offset = (fInfo.format & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ return true;
+ }
+#if SUPPORT_OLD_BINARIES
+ if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_COMPATIBILITY ) {
+ if ( (fInfo.format & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) {
+ offset = 0;
+ return true;
+ }
+ }
+#endif
+ return false;
+ }
+ virtual bool dwarfWithOffset(Registers_x86&, uint32_t& offset) const {
+ if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
+ offset = (fInfo.format & UNWIND_X86_DWARF_SECTION_OFFSET);
+ return true;
+ }
+#if SUPPORT_OLD_BINARIES
+ if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_COMPATIBILITY ) {
+ if ( (fInfo.format & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) {
+ offset = 0;
+ return true;
+ }
+ }
+#endif
+ return false;
+ }
+ virtual bool dwarfWithOffset(Registers_ppc&, uint32_t& offset) const { return true; }
+
+
+ virtual compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); }
+ virtual compact_unwind_encoding_t dwarfEncoding(Registers_x86_64&) const { return UNWIND_X86_64_MODE_DWARF; }
+ virtual compact_unwind_encoding_t dwarfEncoding(Registers_x86&) const { return UNWIND_X86_MODE_DWARF; }
+ virtual compact_unwind_encoding_t dwarfEncoding(Registers_ppc&) const { return 0; }
+
+ unw_proc_info_t fInfo;
+ R fRegisters;
+ A& fAddressSpace;
+ bool fUnwindInfoMissing;
+ bool fIsSignalFrame;
+};
+
+typedef UnwindCursor<LocalAddressSpace,Registers_x86> AbstractUnwindCursor;
+
+template <typename A, typename R>
+UnwindCursor<A,R>::UnwindCursor(unw_context_t* context, A& as)
+ : fRegisters(context), fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false)
+{
+ COMPILE_TIME_ASSERT( sizeof(UnwindCursor<A,R>) < sizeof(unw_cursor_t) );
+
+ bzero(&fInfo, sizeof(fInfo));
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::validReg(int regNum)
+{
+ return fRegisters.validRegister(regNum);
+}
+
+template <typename A, typename R>
+uint64_t UnwindCursor<A,R>::getReg(int regNum)
+{
+ return fRegisters.getRegister(regNum);
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::getReg(int regNum, uint64_t *valp)
+{
+ *valp = fRegisters.getRegister(regNum);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::setReg(int regNum, uint64_t value)
+{
+ fRegisters.setRegister(regNum, value);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::validFloatReg(int regNum)
+{
+ return fRegisters.validFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+double UnwindCursor<A,R>::getFloatReg(int regNum)
+{
+ return fRegisters.getFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::getFloatReg(int regNum, double *valp)
+{
+ *valp = fRegisters.getFloatRegister(regNum);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::setFloatReg(int regNum, double value)
+{
+ fRegisters.setFloatRegister(regNum, value);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+void UnwindCursor<A,R>::jumpto()
+{
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ fRegisters.jumpto();
+#endif
+}
+
+template <typename A, typename R>
+const char* UnwindCursor<A,R>::getRegisterName(int regNum)
+{
+ return fRegisters.getRegisterName(regNum);
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::isSignalFrame()
+{
+ return fIsSignalFrame;
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE)
+{
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ bool foundFDE = false;
+ bool foundInCache = false;
+ // if compact encoding table gave offset into dwarf section, go directly there
+ if ( sectionOffsetOfFDE != 0 ) {
+ foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, ehSectionStart+sectionOffsetOfFDE, &fdeInfo, &cieInfo);
+ }
+#if !FOR_DYLD
+ if ( !foundFDE ) {
+ // otherwise, search cache of previously found FDEs
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(mh, pc);
+ //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%llX) cachedFDE=0x%llX\n", (uint64_t)pc, (uint64_t)cachedFDE);
+ if ( cachedFDE != 0 ) {
+ foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, cachedFDE, &fdeInfo, &cieInfo);
+ foundInCache = foundFDE;
+ //fprintf(stderr, "cachedFDE=0x%llX, foundInCache=%d\n", (uint64_t)cachedFDE, foundInCache);
+ }
+ }
+#endif
+ if ( !foundFDE ) {
+ // still not found, do full scan of __eh_frame section
+ foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, 0, &fdeInfo, &cieInfo);
+ }
+ if ( foundFDE ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ // save off parsed FDE info
+ fInfo.start_ip = fdeInfo.pcStart;
+ fInfo.end_ip = fdeInfo.pcEnd;
+ fInfo.lsda = fdeInfo.lsda;
+ fInfo.handler = cieInfo.personality;
+ fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
+ fInfo.flags = 0;
+ fInfo.format = dwarfEncoding();
+ fInfo.unwind_info = fdeInfo.fdeStart;
+ fInfo.unwind_info_size = fdeInfo.fdeLength;
+ fInfo.extra = (unw_word_t)mh;
+ if ( !foundInCache && (sectionOffsetOfFDE == 0) ) {
+ // don't add to cache entries the compact encoding table can find quickly
+ //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%0llX), mh=0x%llX, start_ip=0x%0llX, fde=0x%0llX, personality=0x%0llX\n",
+ // (uint64_t)pc, (uint64_t)mh, fInfo.start_ip, fInfo.unwind_info, fInfo.handler);
+#if !FOR_DYLD
+ DwarfFDECache<A>::add(mh, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart);
+#endif
+ }
+ return true;
+ }
+ }
+ //DEBUG_MESSAGE("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc);
+ return false;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart)
+{
+ const bool log = false;
+ if ( log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)mh);
+
+ const UnwindSectionHeader<A> sectionHeader(fAddressSpace, unwindSectionStart);
+ if ( sectionHeader.version() != UNWIND_SECTION_VERSION )
+ return false;
+
+ // do a binary search of top level index to find page with unwind info
+ uint32_t targetFunctionOffset = pc - mh;
+ const UnwindSectionIndexArray<A> topIndex(fAddressSpace, unwindSectionStart + sectionHeader.indexSectionOffset());
+ uint32_t low = 0;
+ uint32_t high = sectionHeader.indexCount();
+ const uint32_t last = high - 1;
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", mid, low, high, topIndex.functionOffset(mid));
+ if ( topIndex.functionOffset(mid) <= targetFunctionOffset ) {
+ if ( (mid == last) || (topIndex.functionOffset(mid+1) > targetFunctionOffset) ) {
+ low = mid;
+ break;
+ }
+ else {
+ low = mid+1;
+ }
+ }
+ else {
+ high = mid;
+ }
+ }
+ const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low);
+ const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low+1);
+ const pint_t secondLevelAddr = unwindSectionStart+topIndex.secondLevelPagesSectionOffset(low);
+ const pint_t lsdaArrayStartAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low);
+ const pint_t lsdaArrayEndAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low+1);
+ if ( log ) fprintf(stderr, "\tfirst level search for result index=%d to secondLevelAddr=0x%llX\n",
+ low, (uint64_t)secondLevelAddr);
+ // do a binary search of second level page index
+ uint32_t encoding = 0;
+ pint_t funcStart = 0;
+ pint_t funcEnd = 0;
+ pint_t lsda = 0;
+ pint_t personality = 0;
+ uint32_t pageKind = fAddressSpace.get32(secondLevelAddr);
+ if ( pageKind == UNWIND_SECOND_LEVEL_REGULAR ) {
+ // regular page
+ UnwindSectionRegularPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
+ UnwindSectionRegularArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
+ if ( log ) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in regular page starting at secondLevelAddr=0x%llX\n",
+ (uint64_t)targetFunctionOffset, (uint64_t)secondLevelAddr);
+ uint32_t low = 0;
+ uint32_t high = pageHeader.entryCount();
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ if ( pageIndex.functionOffset(mid) <= targetFunctionOffset ) {
+ if ( mid == (uint32_t)(pageHeader.entryCount()-1) ) {
+ // at end of table
+ low = mid;
+ funcEnd = firstLevelNextPageFunctionOffset + mh;
+ break;
+ }
+ else if ( pageIndex.functionOffset(mid+1) > targetFunctionOffset ) {
+ // next is too big, so we found it
+ low = mid;
+ funcEnd = pageIndex.functionOffset(low+1) + mh;
+ break;
+ }
+ else {
+ low = mid+1;
+ }
+ }
+ else {
+ high = mid;
+ }
+ }
+ encoding = pageIndex.encoding(low);
+ funcStart = pageIndex.functionOffset(low) + mh;
+ if ( pc < funcStart ) {
+ if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
+ return false;
+ }
+ if ( pc > funcEnd ) {
+ if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
+ return false;
+ }
+ }
+ else if ( pageKind == UNWIND_SECOND_LEVEL_COMPRESSED ) {
+ // compressed page
+ UnwindSectionCompressedPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
+ UnwindSectionCompressedArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ const uint32_t targetFunctionPageOffset = targetFunctionOffset - firstLevelFunctionOffset;
+ // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
+ if ( log ) fprintf(stderr, "\tbinary search of compressed page starting at secondLevelAddr=0x%llX\n", (uint64_t)secondLevelAddr);
+ uint32_t low = 0;
+ const uint32_t last = pageHeader.entryCount() - 1;
+ uint32_t high = pageHeader.entryCount();
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ if ( pageIndex.functionOffset(mid) <= targetFunctionPageOffset ) {
+ if ( (mid == last) || (pageIndex.functionOffset(mid+1) > targetFunctionPageOffset) ) {
+ low = mid;
+ break;
+ }
+ else {
+ low = mid+1;
+ }
+ }
+ else {
+ high = mid;
+ }
+ }
+ funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + mh;
+ if ( low < last )
+ funcEnd = pageIndex.functionOffset(low+1) + firstLevelFunctionOffset + mh;
+ else
+ funcEnd = firstLevelNextPageFunctionOffset + mh;
+ if ( pc < funcStart ) {
+ DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcStart=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart);
+ return false;
+ }
+ if ( pc > funcEnd ) {
+ DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcEnd);
+ return false;
+ }
+ uint16_t encodingIndex = pageIndex.encodingIndex(low);
+ if ( encodingIndex < sectionHeader.commonEncodingsArrayCount() ) {
+ // encoding is in common table in section header
+ encoding = fAddressSpace.get32(unwindSectionStart+sectionHeader.commonEncodingsArraySectionOffset()+encodingIndex*sizeof(uint32_t));
+ }
+ else {
+ // encoding is in page specific table
+ uint16_t pageEncodingIndex = encodingIndex-sectionHeader.commonEncodingsArrayCount();
+ encoding = fAddressSpace.get32(secondLevelAddr+pageHeader.encodingsPageOffset()+pageEncodingIndex*sizeof(uint32_t));
+ }
+ }
+ else {
+ DEBUG_MESSAGE("malformed __unwind_info at 0x%0llX bad second level page\n", (uint64_t)unwindSectionStart);
+ return false;
+ }
+
+ // look up LSDA, if encoding says function has one
+ if ( encoding & UNWIND_HAS_LSDA ) {
+ UnwindSectionLsdaArray<A> lsdaIndex(fAddressSpace, lsdaArrayStartAddr);
+ uint32_t funcStartOffset = funcStart - mh;
+ uint32_t low = 0;
+ uint32_t high = (lsdaArrayEndAddr-lsdaArrayStartAddr)/sizeof(unwind_info_section_header_lsda_index_entry);
+ // binary search looks for entry with exact match for functionOffset
+ if ( log ) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset);
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ if ( lsdaIndex.functionOffset(mid) == funcStartOffset ) {
+ lsda = lsdaIndex.lsdaOffset(mid) + mh;
+ break;
+ }
+ else if ( lsdaIndex.functionOffset(mid) < funcStartOffset ) {
+ low = mid+1;
+ }
+ else {
+ high = mid;
+ }
+ }
+ if ( lsda == 0 ) {
+ DEBUG_MESSAGE("found encoding 0x%08X with HAS_LSDA bit set for pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t)pc);
+ return false;
+ }
+ }
+
+ // extact personality routine, if encoding says function has one
+ uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK));
+ if ( personalityIndex != 0 ) {
+ --personalityIndex; // change 1-based to zero-based index
+ if ( personalityIndex > sectionHeader.personalityArrayCount() ) {
+ DEBUG_MESSAGE("found encoding 0x%08X with personality index %d, but personality table has only %d entires\n",
+ encoding, personalityIndex, sectionHeader.personalityArrayCount());
+ return false;
+ }
+ int32_t personalityDelta = fAddressSpace.get32(unwindSectionStart+sectionHeader.personalityArraySectionOffset()+personalityIndex*sizeof(uint32_t));
+ pint_t personalityPointer = personalityDelta + mh;
+ personality = fAddressSpace.getP(personalityPointer);
+ if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), personalityDelta=0x%08X, personality=0x%08llX\n",
+ (uint64_t)pc, personalityDelta, (uint64_t)personality);
+ }
+
+ if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n",
+ (uint64_t)pc, encoding, (uint64_t)lsda, (uint64_t)funcStart);
+ fInfo.start_ip = funcStart;
+ fInfo.end_ip = funcEnd;
+ fInfo.lsda = lsda;
+ fInfo.handler = personality;
+ fInfo.gp = 0;
+ fInfo.flags = 0;
+ fInfo.format = encoding;
+ fInfo.unwind_info = 0;
+ fInfo.unwind_info_size = 0;
+ fInfo.extra = mh;
+ return true;
+}
+
+template <typename A, typename R>
+void UnwindCursor<A,R>::setInfoBasedOnIPRegister(bool isReturnAddress)
+{
+ pint_t pc = this->getReg(UNW_REG_IP);
+
+ // if the last line of a function is a "throw" the compile 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;
+
+ // ask address space object to find unwind sections for this pc
+ pint_t mh;
+ pint_t dwarfStart;
+ pint_t dwarfLength;
+ pint_t compactStart;
+ if ( fAddressSpace.findUnwindSections(pc, mh, dwarfStart, dwarfLength, compactStart) ) {
+ // if there is a compact unwind encoding table, look there first
+ if ( compactStart != 0 ) {
+ if ( this->getInfoFromCompactEncodingSection(pc, mh, compactStart) ) {
+#if !FOR_DYLD
+ // found info in table, done unless encoding says to use dwarf
+ uint32_t offsetInDwarfSection;
+ if ( (dwarfStart != 0) && dwarfWithOffset(offsetInDwarfSection) ) {
+ if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, offsetInDwarfSection) ) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+#endif
+ // if unwind table has entry, but entry says there is no unwind info, note that
+ if ( fInfo.format == 0 )
+ fUnwindInfoMissing = true;
+
+ // old compact encoding
+ if ( !mustUseDwarf() ) {
+ return;
+ }
+ }
+ }
+#if !FOR_DYLD || __ppc__
+ // if there is dwarf unwind info, look there next
+ if ( dwarfStart != 0 ) {
+ if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, 0) ) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+#endif
+ }
+
+#if !FOR_DYLD
+ // the PC is not in code loaded by dyld, look through __register_frame() registered FDEs
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
+ if ( cachedFDE != 0 ) {
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, cachedFDE, &fdeInfo, &cieInfo);
+ if ( msg == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ // save off parsed FDE info
+ fInfo.start_ip = fdeInfo.pcStart;
+ fInfo.end_ip = fdeInfo.pcEnd;
+ fInfo.lsda = fdeInfo.lsda;
+ fInfo.handler = cieInfo.personality;
+ fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
+ fInfo.flags = 0;
+ fInfo.format = dwarfEncoding();
+ fInfo.unwind_info = fdeInfo.fdeStart;
+ fInfo.unwind_info_size = fdeInfo.fdeLength;
+ fInfo.extra = 0;
+ return;
+ }
+ }
+ }
+
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ // lastly check for old style keymgr registration of dynamically generated FDEs
+
+ // acquire exclusive access to libgcc_object_info
+ libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
+ if ( head != NULL ) {
+ // look at each FDE in keymgr
+ for (libgcc_object* ob = head->unseen_objects; ob != NULL; ob = ob->next) {
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, (pint_t)ob->fde, &fdeInfo, &cieInfo);
+ if ( msg == NULL ) {
+ // see if this FDE is for a function that includes the pc we are looking for
+ if ( (fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd) ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ // save off parsed FDE info
+ fInfo.start_ip = fdeInfo.pcStart;
+ fInfo.end_ip = fdeInfo.pcEnd;
+ fInfo.lsda = fdeInfo.lsda;
+ fInfo.handler = cieInfo.personality;
+ fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
+ fInfo.flags = 0;
+ fInfo.format = dwarfEncoding();
+ fInfo.unwind_info = fdeInfo.fdeStart;
+ fInfo.unwind_info_size = fdeInfo.fdeLength;
+ fInfo.extra = 0;
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
+ return;
+ }
+ }
+ }
+ }
+ }
+ // release libgcc_object_info
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
+#endif // !SUPPORT_REMOTE_UNWINDING
+
+#endif // !FOR_DYLD
+
+ // no unwind info, flag that we can't reliable unwind
+ fUnwindInfoMissing = true;
+}
+
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::step()
+{
+ // bottom of stack is defined as when no more unwind info
+ if ( fUnwindInfoMissing )
+ return UNW_STEP_END;
+
+ // apply unwinding to register set
+ int result;
+ if ( this->mustUseDwarf() )
+ result = this->stepWithDwarfFDE();
+ else
+ result = this->stepWithCompactEncoding();
+
+ // update info based on new PC
+ if ( result == UNW_STEP_SUCCESS ) {
+ this->setInfoBasedOnIPRegister(true);
+ if ( fUnwindInfoMissing )
+ return UNW_STEP_END;
+ }
+
+ return result;
+}
+
+
+template <typename A, typename R>
+void UnwindCursor<A,R>::getInfo(unw_proc_info_t* info)
+{
+ *info = fInfo;
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::getFunctionName(char* buf, size_t bufLen, unw_word_t* offset)
+{
+ return fAddressSpace.findFunctionName(this->getReg(UNW_REG_IP), buf, bufLen, offset);
+}
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+template <typename A, typename R>
+class RemoteUnwindCursor : UnwindCursor<A,R>
+{
+public:
+ typedef typename A::pint_t pint_t;
+ RemoteUnwindCursor(A& as, unw_context_t* regs, void* arg);
+ virtual bool validReg(int);
+ virtual int getReg(int r, uint64_t*);
+ virtual int setReg(int, uint64_t);
+ virtual bool validFloatReg(int);
+ virtual int getFloatReg(int, double*);
+ virtual int setFloatReg(int, double);
+ virtual const char* getRegisterName(int);
+ virtual int step();
+ virtual void setRemoteContext(void*);
+ virtual bool remoteUnwindCursor () const {return this->fAddressSpace.getRemoteProcInfo() != NULL; }
+ virtual int endOfPrologueInsns(unw_word_t, unw_word_t, unw_word_t*);
+ void operator delete(void* p, size_t size) {}
+private:
+ virtual bool caller_regno_to_unwind_regno (int, int&);
+
+ bool fIsLeafFrame;
+ bool fIsFirstFrame;
+ void* fArg;
+};
+
+typedef RemoteUnwindCursor<LocalAddressSpace,Registers_x86_64> AbstractRemoteUnwindCursor;
+
+template <typename A, typename R>
+RemoteUnwindCursor<A,R>::RemoteUnwindCursor(A& as, unw_context_t* regs, void* arg)
+ : UnwindCursor<A,R>::UnwindCursor(regs, as), fIsFirstFrame (false), fIsLeafFrame(false), fArg(arg)
+{
+ COMPILE_TIME_ASSERT( sizeof(RemoteUnwindCursor<A,R>) < sizeof(unw_cursor_t) );
+}
+
+template <typename A, typename R>
+bool RemoteUnwindCursor<A,R>::validReg(int r)
+{
+ int unwind_regno;
+ if (!caller_regno_to_unwind_regno(r, unwind_regno))
+ return false;
+ return UnwindCursor<A,R>::fRegisters.validRegister(unwind_regno);
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::getReg(int regNum, uint64_t *valp)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("getRemoteReg called with a local unwind, use getReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // we always return nonvolatile registers. If we have the entire register state available
+ // for this frame then we can return any register requested.
+ if (regmap->nonvolatile_reg_p (regNum) == true || fIsLeafFrame == true) {
+ return this->UnwindCursor<A,R>::getReg (unwind_regno, valp);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::setReg(int regNum, uint64_t val)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("setRemoteReg called with a local unwind, use setReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // Only allow the registers to be set if the unwind cursor is pointing to the
+ // first frame. We need to track where registers were retrieved from in memory
+ // in every other frame. Until then, we prohibit register setting in all but
+ // the first frame.
+ if (fIsFirstFrame) {
+ return this->setReg(unwind_regno, val);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+template <typename A, typename R>
+bool RemoteUnwindCursor<A,R>::validFloatReg(int r)
+{
+ int unwind_regno;
+ if (!caller_regno_to_unwind_regno(r, unwind_regno))
+ return false;
+ return UnwindCursor<A,R>::fRegisters.validFloatRegister(unwind_regno);
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::getFloatReg(int regNum, double *valp)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("getRemoteReg called with a local unwind, use getReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // we always return nonvolatile registers. If we have the entire register state available
+ // for this frame then we can return any register requested.
+ if (regmap->nonvolatile_reg_p (regNum) == true || fIsLeafFrame == true) {
+ return this->UnwindCursor<A,R>::getFloatReg (unwind_regno, valp);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::setFloatReg(int regNum, double val)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("setRemoteReg called with a local unwind, use setReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // Only allow the registers to be set if the unwind cursor is pointing to the
+ // first frame. We need to track where registers were retrieved from in memory
+ // in every other frame. Until then, we prohibit register setting in all but
+ // the first frame.
+ if (fIsFirstFrame) {
+ return this->setFloatReg(unwind_regno, val);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+
+template <typename A, typename R>
+const char* RemoteUnwindCursor<A,R>::getRegisterName(int r)
+{
+ int t;
+ if (!this->caller_regno_to_unwind_regno(r, t))
+ return NULL;
+ r = t;
+ return this->UnwindCursor<A,R>::getRegisterName(r);
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::step()
+{
+ pint_t pc = this->UnwindCursor<A,R>::getReg(UNW_REG_IP);
+ pint_t sp = this->UnwindCursor<A,R>::getReg(UNW_REG_SP);
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo();
+ bool frame_is_sigtramp = false;
+ bool frame_is_inferior_function_call_dummy = false;
+
+ if (procinfo == NULL) {
+ ABORT("stepRemote called with local unwind, use step() instead.");
+ return UNW_EUNSPEC;
+ }
+ struct timeval *step_remote = procinfo->timestamp_start();
+ procinfo->logVerbose ("stepRemote stepping out of frame with pc value 0x%llx", pc);
+
+ // We'll be off of the first frame once we finish this step.
+ fIsFirstFrame = false;
+
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_sigtramp != NULL
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_sigtramp (procinfo->wrap(), pc, fArg)) {
+ frame_is_sigtramp = true;
+ }
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_inferior_function_call != NULL
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_inferior_function_call (procinfo->wrap(), pc, sp, fArg)) {
+ frame_is_inferior_function_call_dummy = true;
+ }
+
+ // If the function we're unwinding can't be a leaf function,
+ // use the eh_frame or compact unwind info if possible.
+ // The caller should pass couldBeLeafFunc == 0 on the first step of a new context
+ // but we can't trust them in that.
+
+ if ((fIsLeafFrame == false && frame_is_inferior_function_call_dummy == false)
+ || frame_is_sigtramp) {
+ R saved_registers(UnwindCursor<A,R>::fRegisters);
+ this->setInfoBasedOnIPRegister(true);
+ // bottom of stack is defined as when no more unwind info
+ if ( !UnwindCursor<A,R>::fUnwindInfoMissing ) {
+ int result;
+ const char *method;
+ if ( this->mustUseDwarf() ) {
+ result = this->stepWithDwarfFDE();
+ method = "dwarf";
+ }
+ else {
+ result = this->stepWithCompactEncoding();
+ method = "compact unwind";
+ }
+ if ( result == UNW_STEP_SUCCESS ) {
+ procinfo->logInfo ("Stepped via %s", method);
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ if (frame_is_sigtramp)
+ fIsLeafFrame = true;
+ return result;
+ }
+ }
+ UnwindCursor<A,R>::fRegisters = saved_registers;
+ }
+
+ if (frame_is_sigtramp || frame_is_inferior_function_call_dummy)
+ fIsLeafFrame = true; // this will be true once we complete this stepRemote()
+ else
+ fIsLeafFrame = false;
+
+ if (frame_is_inferior_function_call_dummy) {
+ if (stepOutOfDebuggerDummyFrame (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, procinfo, pc, sp, fArg) == UNW_STEP_SUCCESS) {
+ procinfo->logInfo ("Stepped via stepOutOfDebuggerDummyFrame");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return UNW_STEP_SUCCESS;
+ }
+ }
+
+ // If we haven't already seen this function we'll need to get the function bounds via
+ // eh frame info (if available) - it's the most accurate function bounds in a
+ // stripped binary. After that we'll ask the driver program (via the get_proc_bounds accessor).
+
+ if (procinfo->haveProfile (pc) == false) {
+
+ uint64_t text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, mh;
+ uint64_t start_addr, end_addr;
+ if (pc == 0) {
+ int ret = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return ret;
+ }
+
+ // If the address is not contained in any image's address range either we've walked off
+ // the stack into random memory or we're backtracing through jit'ed code on the heap.
+ // Let's assume the latter and follow the architecture's default stack walking scheme.
+
+ if (!procinfo->getImageAddresses (pc, mh, text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, fArg)) {
+ int ret = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return ret;
+ }
+ if (procinfo->haveFuncBounds (mh) == false) {
+ struct timeval *get_func_bounds = procinfo->timestamp_start();
+ std::vector<FuncBounds> func_bounds;
+ // CFI entries are usually around 38 bytes but under-estimate a bit
+ // because we're not distinguishing between CIEs and FDEs.
+ if (eh_frame_len > 0)
+ func_bounds.reserve (eh_frame_len / 16);
+ if (procinfo->getCachingPolicy() != UNW_CACHE_NONE) {
+ // cache the entire eh frame section - we'll need to read the whole
+ // thing anyway so we might as well save it.
+ uint8_t *eh_buf = (uint8_t *)malloc (eh_frame_len);
+ if (UnwindCursor<A,R>::fAddressSpace.getBytes (eh_frame_start, eh_frame_len, eh_buf) == 0)
+ return UNW_EUNSPEC;
+ RemoteMemoryBlob *ehmem = new RemoteMemoryBlob(eh_buf, free, eh_frame_start, eh_frame_len, mh, NULL);
+ procinfo->addMemBlob (ehmem);
+ }
+
+ if (CFI_Parser<A>::functionFuncBoundsViaFDE(UnwindCursor<A,R>::fAddressSpace, eh_frame_start, eh_frame_len, func_bounds)) {
+ procinfo->addFuncBounds(mh, func_bounds);
+ procinfo->logVerbose ("Added %d function bounds", (int) func_bounds.size());
+ procinfo->timestamp_stop (get_func_bounds, "getting function bounds from EH frame FDEs");
+ }
+ }
+ if (procinfo->findStartAddr (pc, start_addr, end_addr)) {
+ // If end_addr is 0, we might be looking at the final function in this binary image
+ if (start_addr != 0 && end_addr == 0)
+ end_addr = text_end;
+ procinfo->logVerbose ("Got function bounds from func bounds vector, 0x%llx-0x%llx", start_addr, end_addr);
+ } else {
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()->get_proc_bounds (procinfo->wrap(), pc, &start_addr, &end_addr, fArg) != UNW_ESUCCESS) {
+ int ret = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return ret;
+ }
+ else {
+ procinfo->logVerbose ("Got function bounds from get_proc_bounds callback, 0x%llx-0x%llx", start_addr, end_addr);
+ }
+ }
+ if (start_addr != 0) {
+ procinfo->addProfile (UnwindCursor<A,R>::fAddressSpace.accessors(), UnwindCursor<A,R>::fAddressSpace.wrap(), start_addr, end_addr, fArg);
+ }
+ }
+
+ RemoteUnwindProfile *profile = procinfo->findProfile (pc);
+ if (profile == NULL)
+ return UNW_ENOINFO;
+
+ int retval = stepWithAssembly (UnwindCursor<A,R>::fAddressSpace, pc, profile, UnwindCursor<A,R>::fRegisters);
+ if (retval >= 0) {
+ procinfo->logInfo ("Stepped via stepWithAssembly");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return retval;
+ }
+
+ retval = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return retval;
+}
+
+template <typename A, typename R>
+void RemoteUnwindCursor<A,R>::setRemoteContext(void *arg)
+{
+ // fill in the register state for the currently executing frame.
+ getRemoteContext (UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo(), UnwindCursor<A,R>::fRegisters, arg);
+
+ // Flag that this unwind cursor is pointing at the zeroth frame. We don't
+ // want to use compact unwind info / eh frame info to unwind out of this
+ // frame.
+
+ fIsLeafFrame = true;
+ fIsFirstFrame = true;
+}
+
+// This needs to be done in many of the functions and in libuwind.cxx in one or two
+// places so I'm defining a convenience method.
+template <typename A, typename R>
+bool RemoteUnwindCursor<A,R>::caller_regno_to_unwind_regno (int caller_regno, int& unwind_regno)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ unwind_regno = caller_regno;
+ return true;
+ }
+ if (procinfo->getRegisterMap()->caller_regno_to_unwind_regno (caller_regno, unwind_regno))
+ return true;
+ return false;
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::endOfPrologueInsns (unw_word_t start, unw_word_t end, unw_word_t *endofprologue)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo();
+ *endofprologue = start;
+ if (procinfo == NULL) {
+ ABORT("findEndOfPrologueSetup called with local unwind.");
+ return UNW_EUNSPEC;
+ }
+ if (procinfo->haveProfile (start) == false) {
+ uint64_t text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, mh;
+ if (!procinfo->getImageAddresses (start, mh, text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, fArg))
+ return UNW_EUNSPEC;
+ if (end == 0) {
+ if (procinfo->haveFuncBounds (mh) == false) {
+ std::vector<FuncBounds> func_bounds;
+ // CFI entries are usually around 38 bytes but under-estimate a bit
+ // because we're not distinguishing between CIEs and FDEs.
+ if (eh_frame_len > 0)
+ func_bounds.reserve (eh_frame_len / 16);
+ if (procinfo->getCachingPolicy() != UNW_CACHE_NONE) {
+ // cache the entire eh frame section - we'll need to read the whole
+ // thing anyway so we might as well save it.
+ uint8_t *eh_buf = (uint8_t *)malloc (eh_frame_len);
+ if (UnwindCursor<A,R>::fAddressSpace.getBytes (eh_frame_start, eh_frame_len, eh_buf) == 0)
+ return UNW_EUNSPEC;
+ RemoteMemoryBlob *ehmem = new RemoteMemoryBlob(eh_buf, free, eh_frame_start, eh_frame_len, mh, NULL);
+ procinfo->addMemBlob (ehmem);
+ }
+ if (CFI_Parser<A>::functionFuncBoundsViaFDE(UnwindCursor<A,R>::fAddressSpace, eh_frame_start, eh_frame_len, func_bounds)) {
+ procinfo->addFuncBounds(mh, func_bounds);
+ }
+ }
+ uint64_t bounded_start, bounded_end;
+ if (procinfo->findStartAddr (start, bounded_start, bounded_end)) {
+ end = bounded_end;
+ } else {
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()->get_proc_bounds (procinfo->wrap(), start, &bounded_start, &bounded_end, fArg) != UNW_ESUCCESS)
+ if (bounded_end != 0)
+ end = bounded_end;
+ }
+ }
+ if (procinfo->addProfile (UnwindCursor<A,R>::fAddressSpace.accessors(), UnwindCursor<A,R>::fAddressSpace.wrap(), start, end, fArg) == false)
+ return UNW_EUNSPEC;
+ }
+ RemoteUnwindProfile *profile = procinfo->findProfile (start);
+ if (profile == NULL)
+ return UNW_ENOINFO;
+ *endofprologue = profile->fFirstInsnPastPrologue;
+ return UNW_ESUCCESS;
+}
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+
+}; // namespace lldb_private
+
+
+#endif // __UNWINDCURSOR_HPP__
OpenPOWER on IntegriCloud