summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Utility
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Utility')
-rw-r--r--lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp327
-rw-r--r--lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h83
-rw-r--r--lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp306
-rw-r--r--lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h22
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp255
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h83
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp73
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h66
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp243
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h77
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h509
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h212
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h213
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp456
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp115
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp147
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp409
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp1019
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp1686
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp869
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp135
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h89
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp985
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s261
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp88
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp977
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp405
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h85
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c466
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp1307
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c282
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c443
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h245
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h35
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx421
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s229
36 files changed, 13623 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp
new file mode 100644
index 00000000000..bf6b6c2eac4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp
@@ -0,0 +1,327 @@
+//===-- LibUnwindRegisterContext.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibUnwindRegisterContext.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// LibUnwindRegisterContext constructor
+//----------------------------------------------------------------------
+LibUnwindRegisterContext::LibUnwindRegisterContext
+(
+ Thread &thread,
+ StackFrame *frame,
+ const lldb_private::unw_cursor_t& unwind_cursor
+) :
+ RegisterContext (thread, frame),
+ m_unwind_cursor (unwind_cursor),
+ m_unwind_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+LibUnwindRegisterContext::~LibUnwindRegisterContext()
+{
+}
+
+void
+LibUnwindRegisterContext::Invalidate ()
+{
+ m_unwind_cursor_is_valid = false;
+}
+
+size_t
+LibUnwindRegisterContext::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const lldb::RegisterInfo *
+LibUnwindRegisterContext::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+LibUnwindRegisterContext::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const lldb::RegisterSet *
+LibUnwindRegisterContext::GetRegisterSet (uint32_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+LibUnwindRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ if (m_unwind_cursor_is_valid == false)
+ return false;
+
+ // Read the register
+ unw_word_t reg_value;
+ if (unw_get_reg (&m_unwind_cursor, reg, &reg_value) != UNW_ESUCCESS)
+ return false;
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (uint32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingSint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (int32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (int64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ if (reg_info->byte_size > sizeof(unw_word_t))
+ return false;
+
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+ }
+ break;
+ }
+ return false;
+}
+
+
+bool
+LibUnwindRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ Scalar reg_value;
+
+ if (ReadRegisterValue (reg, reg_value))
+ {
+ if (reg_value.GetData(data))
+ {
+ // "reg_value" is local and now "data" points to the data within
+ // "reg_value", so we must make a copy that will live within "data"
+ DataBufferSP data_sp (new DataBufferHeap (data.GetDataStart(), data.GetByteSize()));
+ data.SetData (data_sp, 0, data.GetByteSize());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+LibUnwindRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+ unw_word_t reg_value;
+ switch (value.GetType())
+ {
+ case Scalar::e_sint: reg_value = value.SInt(); break;
+ case Scalar::e_uint: reg_value = value.UInt(); break;
+ case Scalar::e_slong: reg_value = value.SLong(); break;
+ case Scalar::e_ulong: reg_value = value.ULong(); break;
+ case Scalar::e_slonglong: reg_value = value.SLongLong(); break;
+ case Scalar::e_ulonglong: reg_value = value.ULongLong(); break;
+ case Scalar::e_float:
+ if (sizeof (float) == sizeof (unsigned int))
+ reg_value = value.UInt();
+ else if (sizeof (float) == sizeof (unsigned long))
+ reg_value = value.ULong();
+ else if (sizeof (float) == sizeof (unsigned long long))
+ reg_value = value.ULongLong();
+ else
+ return false;
+ break;
+
+ case Scalar::e_double:
+ if (sizeof (double) == sizeof (unsigned int))
+ reg_value = value.UInt();
+ else if (sizeof (double) == sizeof (unsigned long))
+ reg_value = value.ULong();
+ else if (sizeof (double) == sizeof (unsigned long long))
+ reg_value = value.ULongLong();
+ else
+ return false;
+ break;
+
+ case Scalar::e_long_double:
+ if (sizeof (long double) == sizeof (unsigned int))
+ reg_value = value.UInt();
+ else if (sizeof (long double) == sizeof (unsigned long))
+ reg_value = value.ULong();
+ else if (sizeof (long double) == sizeof (unsigned long long))
+ reg_value = value.ULongLong();
+ else
+ return false;
+ break;
+ }
+
+ return unw_set_reg (&m_unwind_cursor, reg, reg_value) == UNW_ESUCCESS;
+}
+
+
+bool
+LibUnwindRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+
+ if (reg_info == NULL)
+ return false;
+ if (reg_info->byte_size > sizeof (unw_word_t))
+ return false;
+
+ Scalar value;
+ uint32_t offset = data_offset;
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ if (reg_info->byte_size <= 4)
+ value = data.GetMaxU32 (&offset, reg_info->byte_size);
+ else if (reg_info->byte_size <= 8)
+ value = data.GetMaxU64 (&offset, reg_info->byte_size);
+ else
+ return false;
+ break;
+
+ case eEncodingSint:
+ if (reg_info->byte_size <= 4)
+ value = (int32_t)data.GetMaxU32 (&offset, reg_info->byte_size);
+ else if (reg_info->byte_size <= 8)
+ value = data.GetMaxS64 (&offset, reg_info->byte_size);
+ else
+ return false;
+ break;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ value = data.GetFloat (&offset);
+ break;
+
+ case sizeof (double):
+ value = data.GetDouble (&offset);
+ break;
+
+ case sizeof (long double):
+ value = data.GetLongDouble (&offset);
+ break;
+ default:
+ return false;
+ }
+ }
+ return WriteRegisterValue (reg, value);
+}
+
+
+bool
+LibUnwindRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ // libunwind frames can't handle this it doesn't always have all register
+ // values. This call should only be called on frame zero anyway so there
+ // shouldn't be any problem
+ return false;
+}
+
+bool
+LibUnwindRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ // Since this class doesn't respond to "ReadAllRegisterValues()", it must
+ // not have been the one that saved all the register values. So we just let
+ // the thread's register context (the register context for frame zero) do
+ // the writing.
+ return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp);
+}
+
+
+uint32_t
+LibUnwindRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
diff --git a/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h
new file mode 100644
index 00000000000..4e89b27961f
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h
@@ -0,0 +1,83 @@
+//===-- LibUnwindRegisterContext.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_LibUnwindRegisterContext_h_
+#define lldb_LibUnwindRegisterContext_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "libunwind.h"
+
+class LibUnwindRegisterContext : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ LibUnwindRegisterContext (lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame,
+ const lldb_private::unw_cursor_t &unwind_cursor);
+
+ virtual
+ ~LibUnwindRegisterContext ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t reg_set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ lldb_private::unw_cursor_t m_unwind_cursor;
+ bool m_unwind_cursor_is_valid;
+ //------------------------------------------------------------------
+ // For LibUnwindRegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (LibUnwindRegisterContext);
+};
+
+#endif // lldb_LibUnwindRegisterContext_h_
diff --git a/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp
new file mode 100644
index 00000000000..58a7ac043c5
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp
@@ -0,0 +1,306 @@
+//===-- MacOSXLibunwindCallbacks.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MacOSXLibunwindCallbacks_cpp_
+#define liblldb_MacOSXLibunwindCallbacks_cpp_
+#if defined(__cplusplus)
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "lldb-enumerations.h"
+#include "libunwind.h"
+#include "llvm-c/EnhancedDisassembly.h"
+
+using namespace lldb;
+
+namespace lldb_private {
+
+/* Don't implement (libunwind does not use)
+ find_proc_info
+ put_unwind_info
+ get_dyn_info_list_addr
+ access_mem
+ resume
+*/
+/*
+ Should implement (not needed yet)
+ access_fpreg
+ access_vecreg
+ proc_is_sigtramp
+ proc_is_inferior_function_call
+ access_reg_inf_func_call
+*/
+
+static int
+access_reg (lldb_private::unw_addr_space_t as, lldb_private::unw_regnum_t regnum, lldb_private::unw_word_t *valp, int write, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ /* FIXME Only support reading for now. */
+ if (write == 1)
+ return -1;
+ if (th->GetRegisterContext()->GetRegisterInfoAtIndex(regnum) == NULL)
+ return -1;
+ DataExtractor de;
+ if (!th->GetRegisterContext()->ReadRegisterBytes (regnum, de))
+ return -1;
+ memcpy (valp, de.GetDataStart(), de.GetByteSize());
+ return UNW_ESUCCESS;
+}
+
+static int
+get_proc_name (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t ip, char *bufp, size_t buf_len, lldb_private::unw_word_t *offp, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ Address addr;
+ if (!th->GetProcess().ResolveLoadAddress(ip, addr))
+ return -1;
+
+ SymbolContext sc;
+ if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextFunction, sc))
+ return -1;
+ if (!sc.symbol)
+ return -1;
+ strlcpy (bufp, sc.symbol->GetMangled().GetMangledName().AsCString(""), buf_len);
+ if (offp)
+ *offp = addr.GetLoadAddress(&th->GetProcess()) - sc.symbol->GetValue().GetLoadAddress(&th->GetProcess());
+ return UNW_ESUCCESS;
+}
+
+static int
+find_image_info (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t load_addr, lldb_private::unw_word_t *mh,
+ lldb_private::unw_word_t *text_start, lldb_private::unw_word_t *text_end,
+ lldb_private::unw_word_t *eh_frame, lldb_private::unw_word_t *eh_frame_len,
+ lldb_private::unw_word_t *compact_unwind_start, lldb_private::unw_word_t *compact_unwind_len, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ Address addr;
+ if (!th->GetProcess().ResolveLoadAddress(load_addr, addr))
+ return -1;
+
+ SymbolContext sc;
+ if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextModule, sc))
+ return -1;
+
+ SectionList *sl = sc.module_sp->GetObjectFile()->GetSectionList();
+ static ConstString g_segment_name_TEXT("__TEXT");
+ SectionSP text_segment_sp(sl->FindSectionByName(g_segment_name_TEXT));
+ if (!text_segment_sp)
+ return -1;
+
+ *mh = text_segment_sp->GetLoadBaseAddress (&th->GetProcess());
+ *text_start = text_segment_sp->GetLoadBaseAddress (&th->GetProcess());
+ *text_end = *text_start + text_segment_sp->GetByteSize();
+
+ static ConstString g_section_name_eh_frame ("__eh_frame");
+ SectionSP eh_frame_section_sp = text_segment_sp->GetChildren().FindSectionByName(g_section_name_eh_frame);
+ if (eh_frame_section_sp.get()) {
+ *eh_frame = eh_frame_section_sp->GetLoadBaseAddress (&th->GetProcess());
+ *eh_frame_len = eh_frame_section_sp->GetByteSize();
+ } else {
+ *eh_frame = 0;
+ *eh_frame_len = 0;
+ }
+
+ static ConstString g_section_name_unwind_info ("__unwind_info");
+ SectionSP unwind_info_section_sp = text_segment_sp->GetChildren().FindSectionByName(g_section_name_unwind_info);
+ if (unwind_info_section_sp.get()) {
+ *compact_unwind_start = unwind_info_section_sp->GetLoadBaseAddress (&th->GetProcess());
+ *compact_unwind_len = unwind_info_section_sp->GetByteSize();
+ } else {
+ *compact_unwind_start = 0;
+ *compact_unwind_len = 0;
+ }
+ return UNW_ESUCCESS;
+}
+
+static int
+get_proc_bounds (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t ip, lldb_private::unw_word_t *low, lldb_private::unw_word_t *high, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ Address addr;
+ if (!th->GetProcess().ResolveLoadAddress(ip, addr))
+ return -1;
+ SymbolContext sc;
+ if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextFunction | eSymbolContextSymbol, sc))
+ return -1;
+ if (sc.function)
+ {
+ lldb::addr_t start, len;
+ start = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(&th->GetProcess());
+ len = sc.function->GetAddressRange().GetByteSize();
+ if (start == LLDB_INVALID_ADDRESS || len == LLDB_INVALID_ADDRESS)
+ return -1;
+ *low = start;
+ *high = start + len;
+ return UNW_ESUCCESS;
+ }
+ if (sc.symbol)
+ {
+ lldb::addr_t start, len;
+ start = sc.symbol->GetAddressRangeRef().GetBaseAddress().GetLoadAddress(&th->GetProcess());
+ len = sc.symbol->GetAddressRangeRef().GetByteSize();
+ if (start == LLDB_INVALID_ADDRESS)
+ return -1;
+ *low = start;
+ if (len != LLDB_INVALID_ADDRESS)
+ *high = start + len;
+ else
+ *high = 0;
+ return UNW_ESUCCESS;
+ }
+ return -1;
+}
+
+static int
+access_raw (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t addr, lldb_private::unw_word_t extent, uint8_t *valp, int write, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ /* FIXME Only support reading for now. */
+ if (write == 1)
+ return -1;
+
+ Error error;
+ if (th->GetProcess().ReadMemory (addr, valp, extent, error) != extent)
+ return -1;
+ return UNW_ESUCCESS;
+}
+
+
+static int
+reg_info (lldb_private::unw_addr_space_t as, lldb_private::unw_regnum_t regnum, lldb_private::unw_regtype_t *type, char *buf, size_t buflen, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ RegisterContext *regc = th->GetRegisterContext();
+ if (regnum > regc->GetRegisterCount())
+ {
+ *type = UNW_NOT_A_REG;
+ return UNW_ESUCCESS;
+ }
+
+ const char *name = regc->GetRegisterName (regnum);
+ if (name == NULL)
+ {
+ *type = UNW_NOT_A_REG;
+ return UNW_ESUCCESS;
+ }
+ strlcpy (buf, name, buflen);
+
+ const lldb::RegisterInfo *reginfo = regc->GetRegisterInfoAtIndex (regnum);
+ if (reginfo == NULL || reginfo->encoding == eEncodingInvalid)
+ {
+ *type = UNW_NOT_A_REG;
+ return UNW_ESUCCESS;
+ }
+ if (reginfo->encoding == eEncodingUint || reginfo->encoding == eEncodingSint)
+ *type = UNW_INTEGER_REG;
+ if (reginfo->encoding == eEncodingIEEE754)
+ *type = UNW_FLOATING_POINT_REG;
+ if (reginfo->encoding == eEncodingVector)
+ *type = UNW_VECTOR_REG;
+
+ return UNW_ESUCCESS;
+}
+
+
+static int
+read_byte_for_edis (uint8_t *buf, uint64_t addr, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ DataBufferHeap onebyte(1, 0);
+ Error error;
+ if (th->GetProcess().ReadMemory (addr, onebyte.GetBytes(), onebyte.GetByteSize(), error) != 1)
+ return -1;
+ *buf = onebyte.GetBytes()[0];
+ return UNW_ESUCCESS;
+}
+
+static int
+instruction_length (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t addr, int *length, void *arg)
+{
+ EDDisassemblerRef disasm;
+ EDInstRef cur_insn;
+
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ const ArchSpec target_arch (th->GetProcess().GetTarget().GetArchitecture ());
+
+ if (target_arch.GetCPUType() == CPU_TYPE_I386)
+ {
+ if (EDGetDisassembler (&disasm, "i386-apple-darwin", kEDAssemblySyntaxX86ATT) != 0)
+ return -1;
+ }
+ else if (target_arch.GetCPUType() == CPU_TYPE_X86_64)
+ {
+ if (EDGetDisassembler (&disasm, "x86_64-apple-darwin", kEDAssemblySyntaxX86ATT) != 0)
+ return -1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (EDCreateInsts (&cur_insn, 1, disasm, read_byte_for_edis, addr, arg) != 1)
+ return -1;
+ *length = EDInstByteSize (cur_insn);
+ EDReleaseInst (cur_insn);
+ return UNW_ESUCCESS;
+}
+
+lldb_private::unw_accessors_t
+get_macosx_libunwind_callbacks () {
+ lldb_private::unw_accessors_t ap;
+ bzero (&ap, sizeof (lldb_private::unw_accessors_t));
+ ap.find_proc_info = NULL;
+ ap.put_unwind_info = NULL;
+ ap.get_dyn_info_list_addr = NULL;
+ ap.find_image_info = find_image_info;
+ ap.access_mem = NULL;
+ ap.access_reg = access_reg;
+ ap.access_fpreg = NULL;
+ ap.access_vecreg = NULL;
+ ap.resume = NULL;
+ ap.get_proc_name = get_proc_name;
+ ap.get_proc_bounds = get_proc_bounds;
+ ap.access_raw = access_raw;
+ ap.reg_info = reg_info;
+ ap.proc_is_sigtramp = NULL;
+ ap.proc_is_inferior_function_call = NULL;
+ ap.access_reg_inf_func_call = NULL;
+ ap.instruction_length = instruction_length;
+ return ap;
+}
+
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_MacOSXLibunwindCallbacks_cpp_
diff --git a/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h
new file mode 100644
index 00000000000..78bd27b2ad3
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h
@@ -0,0 +1,22 @@
+//===-- MacOSXLibunwindCallbacks.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MacOSXLibunwindCallbacks_h_
+#define liblldb_MacOSXLibunwindCallbacks_h_
+#if defined(__cplusplus)
+
+namespace lldb_private {
+
+unw_accessors_t get_macosx_libunwind_callbacks ();
+
+} // namespace lldb_utility
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_MacOSXLibunwindCallbacks_h_
+
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 00000000000..df2f7c07f65
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -0,0 +1,255 @@
+//===-- RegisterContextMacOSXFrameBackchain.cpp -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+#include "StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMacOSXFrameBackchain constructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain
+(
+ Thread &thread,
+ StackFrame *frame,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor
+) :
+ RegisterContext (thread, frame),
+ m_cursor (cursor),
+ m_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain()
+{
+}
+
+void
+RegisterContextMacOSXFrameBackchain::Invalidate ()
+{
+ m_cursor_is_valid = false;
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const lldb::RegisterInfo *
+RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const lldb::RegisterSet *
+RegisterContextMacOSXFrameBackchain::GetRegisterSet (uint32_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ if (!m_cursor_is_valid)
+ return false;
+
+ uint64_t reg_value = LLDB_INVALID_ADDRESS;
+
+ const RegisterInfo *reg_info = m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ switch (reg_info->kinds[eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC:
+ if (m_cursor.pc == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.pc;
+ break;
+
+ case LLDB_REGNUM_GENERIC_FP:
+ if (m_cursor.fp == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.pc;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (uint32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingSint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (int32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (int64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+ }
+ break;
+ }
+ return false;
+}
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ Scalar reg_value;
+
+ if (ReadRegisterValue (reg, reg_value))
+ {
+ if (reg_value.GetData(data))
+ {
+ // "reg_value" is local and now "data" points to the data within
+ // "reg_value", so we must make a copy that will live within "data"
+ DataBufferSP data_sp (new DataBufferHeap (data.GetDataStart(), data.GetByteSize()));
+ data.SetData (data_sp, 0, data.GetByteSize());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ // Not supported yet. We could easily add support for this by remembering
+ // the address of each entry (it would need to be part of the cursor)
+ return false;
+}
+
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ // Not supported yet. We could easily add support for this by remembering
+ // the address of each entry (it would need to be part of the cursor)
+ return false;
+}
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ // libunwind frames can't handle this it doesn't always have all register
+ // values. This call should only be called on frame zero anyway so there
+ // shouldn't be any problem
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ // Since this class doesn't respond to "ReadAllRegisterValues()", it must
+ // not have been the one that saved all the register values. So we just let
+ // the thread's register context (the register context for frame zero) do
+ // the writing.
+ return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp);
+}
+
+
+uint32_t
+RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
new file mode 100644
index 00000000000..f4118c2795d
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -0,0 +1,83 @@
+//===-- RegisterContextMacOSXFrameBackchain.h -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextMacOSXFrameBackchain_h_
+#define lldb_RegisterContextMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindMacOSXFrameBackchain.h"
+
+class RegisterContextMacOSXFrameBackchain : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMacOSXFrameBackchain (lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor);
+
+ virtual
+ ~RegisterContextMacOSXFrameBackchain ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t reg_set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ UnwindMacOSXFrameBackchain::Cursor m_cursor;
+ bool m_cursor_is_valid;
+ //------------------------------------------------------------------
+ // For RegisterContextMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMacOSXFrameBackchain);
+};
+
+#endif // lldb_RegisterContextMacOSXFrameBackchain_h_
diff --git a/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp
new file mode 100644
index 00000000000..1b6fa58dcd4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp
@@ -0,0 +1,73 @@
+//===-- UnwindLibUnwind.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+#include "UnwindLibUnwind.h"
+#include "LibUnwindRegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindLibUnwind::UnwindLibUnwind (Thread &thread, unw_addr_space_t addr_space) :
+ Unwind (thread),
+ m_addr_space (addr_space),
+ m_cursors()
+{
+ m_pc_regnum = thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ m_sp_regnum = thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+}
+
+uint32_t
+UnwindLibUnwind::GetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ unw_cursor_t cursor;
+ unw_init_remote (&cursor, m_addr_space, &m_thread);
+
+ m_cursors.push_back (cursor);
+
+ while (1)
+ {
+ int stepresult = unw_step (&cursor);
+ if (stepresult > 0)
+ m_cursors.push_back (cursor);
+ else
+ break;
+ }
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindLibUnwind::GetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ {
+ int pc_err = unw_get_reg (&m_cursors[idx], m_pc_regnum, &pc);
+ int sp_err = unw_get_reg (&m_cursors[idx], m_sp_regnum, &cfa);
+ return pc_err == UNW_ESUCCESS && sp_err == UNW_ESUCCESS;
+ }
+ return false;
+}
+
+RegisterContext *
+UnwindLibUnwind::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ uint32_t idx = frame->GetID();
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ return new LibUnwindRegisterContext (m_thread, frame, m_cursors[idx]);
+ return NULL;
+}
diff --git a/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h
new file mode 100644
index 00000000000..d91f164a2f9
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h
@@ -0,0 +1,66 @@
+//===-- UnwindLibUnwind.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindLibUnwind_h_
+#define lldb_UnwindLibUnwind_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "libunwind.h"
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Unwind.h"
+
+class UnwindLibUnwind : public lldb_private::Unwind
+{
+public:
+ UnwindLibUnwind (lldb_private::Thread &thread,
+ lldb_private::unw_addr_space_t addr_space);
+
+ virtual
+ ~UnwindLibUnwind()
+ {
+ }
+
+ virtual void
+ Clear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ GetFrameCount();
+
+ bool
+ GetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ lldb_private::Thread &
+ GetThread();
+
+private:
+ lldb_private::unw_addr_space_t m_addr_space;
+ std::vector<lldb_private::unw_cursor_t> m_cursors;
+ uint32_t m_pc_regnum;
+ uint32_t m_sp_regnum;
+ //------------------------------------------------------------------
+ // For UnwindLibUnwind only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindLibUnwind);
+};
+
+#endif // lldb_UnwindLibUnwind_h_
diff --git a/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
new file mode 100644
index 00000000000..586e3d78864
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
@@ -0,0 +1,243 @@
+//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
+ Unwind (thread),
+ m_cursors()
+{
+}
+
+uint32_t
+UnwindMacOSXFrameBackchain::GetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ const ArchSpec target_arch (m_thread.GetProcess().GetTarget().GetArchitecture ());
+ // Frame zero should always be supplied by the thread...
+ StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (0));
+ if (target_arch == ArchSpec("x86_64"))
+ GetStackFrameData_x86_64 (frame_sp.get());
+ else if (target_arch == ArchSpec("i386"))
+ GetStackFrameData_i386 (frame_sp.get());
+
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindMacOSXFrameBackchain::GetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ {
+ if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
+ return false;
+ if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
+ return false;
+
+ pc = m_cursors[idx].pc;
+ cfa = m_cursors[idx].fp;
+
+ return true;
+ }
+ return false;
+}
+
+RegisterContext *
+UnwindMacOSXFrameBackchain::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ uint32_t idx = frame->GetID();
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ return new RegisterContextMacOSXFrameBackchain (m_thread, frame, m_cursors[idx]);
+ return NULL;
+}
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (StackFrame *first_frame)
+{
+ m_cursors.clear();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ typedef struct Frame_i386
+ {
+ uint32_t fp;
+ uint32_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_i386 frame = { cursor.fp, cursor.pc };
+
+ m_cursors.push_back(cursor);
+
+ const size_t k_frame_size = sizeof(frame);
+ Error error;
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (8 bytes)
+ if (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetPC() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (first_frame_sp && m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+// uint32_t i=0;
+// printf(" PC FP\n");
+// printf(" ------------------ ------------------ \n");
+// for (i=0; i<m_cursors.size(); ++i)
+// {
+// printf("[%3u] 0x%16.16llx 0x%16.16llx\n", i, m_cursors[i].pc, m_cursors[i].fp);
+// }
+ return m_cursors.size();
+}
+
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (StackFrame *first_frame)
+{
+ m_cursors.clear();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ typedef struct Frame_x86_64
+ {
+ uint64_t fp;
+ uint64_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_x86_64 frame = { cursor.fp, cursor.pc };
+
+ m_cursors.push_back(cursor);
+ Error error;
+ const size_t k_frame_size = sizeof(frame);
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (16 bytes)
+ if (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetPC() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return m_cursors.size();
+}
+
diff --git a/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
new file mode 100644
index 00000000000..86ba6e7ae7f
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
@@ -0,0 +1,77 @@
+//===-- UnwindMacOSXFrameBackchain.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindMacOSXFrameBackchain_h_
+#define lldb_UnwindMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Unwind.h"
+
+class UnwindMacOSXFrameBackchain : public lldb_private::Unwind
+{
+public:
+ UnwindMacOSXFrameBackchain (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindMacOSXFrameBackchain()
+ {
+ }
+
+ virtual void
+ Clear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ GetFrameCount();
+
+ bool
+ GetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ lldb_private::Thread &
+ GetThread();
+
+protected:
+ friend class RegisterContextMacOSXFrameBackchain;
+
+ typedef struct Cursor
+ {
+ lldb::addr_t pc; // Program counter
+ lldb::addr_t fp; // Frame pointer for us with backchain
+ };
+
+private:
+ std::vector<Cursor> m_cursors;
+
+ size_t
+ GetStackFrameData_i386 (lldb_private::StackFrame *first_frame);
+
+ size_t
+ GetStackFrameData_x86_64 (lldb_private::StackFrame *first_frame);
+
+ //------------------------------------------------------------------
+ // For UnwindMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindMacOSXFrameBackchain);
+};
+
+#endif // lldb_UnwindMacOSXFrameBackchain_h_
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h b/lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h
new file mode 100644
index 00000000000..63cc8ba2366
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h
@@ -0,0 +1,509 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- libunwind.h ---------------------------------------------*- 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 libuwind
+//
+// Source compatible with Level 1 Base ABI documented at:
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __LIBUNWIND__
+#define __LIBUNWIND__
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <mach/mach_types.h>
+#include <Availability.h>
+
+namespace lldb_private {
+
+#pragma mark Error codes
+
+enum {
+ UNW_ESUCCESS = 0, /* no error */
+ UNW_EUNSPEC = -6540, /* unspecified (general) error */
+ UNW_ENOMEM = -6541, /* out of memory */
+ UNW_EBADREG = -6542, /* bad register number */
+ UNW_EREADONLYREG = -6543, /* attempt to write read-only register */
+ UNW_ESTOPUNWIND = -6544, /* stop unwinding */
+ UNW_EINVALIDIP = -6545, /* invalid IP */
+ UNW_EBADFRAME = -6546, /* bad frame */
+ UNW_EINVAL = -6547, /* unsupported operation or bad value */
+ UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
+ UNW_ENOINFO = -6549, /* no unwind info found */
+ UNW_EREGUNAVAILABLE = -6550 /* contents of requested reg are not available */
+};
+
+#pragma mark General data structures
+
+struct unw_context_t { uint64_t data[128]; };
+typedef struct unw_context_t unw_context_t;
+
+struct unw_cursor_t { uint64_t data[140]; };
+typedef struct unw_cursor_t unw_cursor_t;
+
+enum unw_as_type { UNW_LOCAL, UNW_REMOTE };
+struct unw_addr_space
+{
+ enum unw_as_type type;
+ uint8_t data[];
+};
+typedef struct unw_addr_space* unw_addr_space_t;
+
+typedef int unw_regnum_t;
+typedef uint64_t unw_word_t;
+typedef double unw_fpreg_t;
+
+enum unw_vecreg_format {
+ UNW_VECREG_SIGNED,
+ UNW_VECREG_UNSIGNED,
+ UNW_VECREG_FLOAT
+};
+
+typedef struct
+{
+ union {
+ double doubles[8];
+ float floats [16];
+
+ uint64_t dwords [8];
+ uint32_t words [16];
+ uint16_t hwords [32];
+ uint8_t bytes [64];
+ } data;
+ uint16_t unit_size; // bits
+ uint16_t num_units;
+ uint8_t format;
+} unw_vecreg_t;
+
+struct unw_proc_info_t
+{
+ unw_word_t start_ip; /* start address of function */
+ unw_word_t end_ip; /* address after end of function */
+ unw_word_t lsda; /* address of language specific data area, or zero if not used */
+ unw_word_t handler; /* personality routine, or zero if not used */
+ unw_word_t gp; /* not used */
+ unw_word_t flags; /* not used */
+ uint32_t format; /* compact unwind encoding, or zero if none */
+ uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */
+ unw_word_t unwind_info; /* address of dwarf unwind info, or zero if none */
+ unw_word_t extra; /* mach_header of mach-o image containing function */
+};
+typedef struct unw_proc_info_t unw_proc_info_t;
+
+#pragma mark Local API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int unw_getcontext(unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_init_local(unw_cursor_t*, unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_step(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_reg(unw_cursor_t*, unw_regnum_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_set_reg(unw_cursor_t*, unw_regnum_t, unw_word_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_set_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_resume(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+extern const char* unw_regname(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_proc_info(unw_cursor_t*, unw_proc_info_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_is_fpreg(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_is_signal_frame(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_proc_name(unw_cursor_t*, char*, size_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
+
+
+#pragma mark Remote data structures
+
+typedef enum {
+ UNW_NOT_A_REG = 0,
+ UNW_INTEGER_REG,
+ UNW_FLOATING_POINT_REG,
+ UNW_VECTOR_REG,
+ UNW_OTHER_REG
+} unw_regtype_t;
+
+typedef enum {
+ UNW_TARGET_UNSPECIFIED = 0,
+ UNW_TARGET_I386,
+ UNW_TARGET_X86_64,
+ UNW_TARGET_PPC,
+ UNW_TARGET_ARM
+} unw_targettype_t;
+
+typedef enum {
+ UNW_LOG_LEVEL_NONE = 0x00000000,
+ UNW_LOG_LEVEL_INFO = 0x00000001,
+ UNW_LOG_LEVEL_API = 0x00000002,
+ UNW_LOG_LEVEL_VERBOSE = 0x00000004,
+ UNW_LOG_LEVEL_TIMINGS = 0x00000008,
+ UNW_LOG_LEVEL_DEBUG = 0x00000010,
+ UNW_LOG_LEVEL_ALL = 0x0FFFFFFF
+} unw_log_level_t;
+
+typedef enum {
+ UNW_CACHE_NONE = 0,
+ UNW_CACHE_GLOBAL,
+ UNW_CACHE_PER_THREAD
+} unw_caching_policy_t;
+
+typedef struct {
+ int (*find_proc_info)(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int need_unwind_info, void *arg);
+ int (*put_unwind_info)(unw_addr_space_t as, unw_proc_info_t *pip, void *arg);
+ int (*get_dyn_info_list_addr)(unw_addr_space_t as, unw_word_t *dilap, void *arg);
+
+ // Reads or writes a memory object the size of a target pointer.
+ // Byte-swaps if necessary.
+ int (*access_mem)(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg);
+
+ // Register contents sent as-is (i.e. not byte-swapped).
+ // Register numbers are the driver program's numbering scheme as
+ // determined by the reg_info callbacks; libunwind will interrogate
+ // the driver program to figure out which numbers it uses to refer to
+ // which registers.
+ int (*access_reg)(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg);
+ int (*access_fpreg)(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *valp, int write, void *arg);
+ int (*resume)(unw_addr_space_t as, unw_cursor_t *cp, void *arg);
+ int (*get_proc_name)(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, unw_word_t *offp, void *arg);
+
+
+ // Added to find the start of the image (executable, bundle, dylib, etc)
+ // for a given address.
+ // as - The address space to use
+ // ip - The address libunwind wants to know about
+ // mh - The Mach-O header address for this image
+ // text_start - The start of __TEXT segment (all its sections)
+ // text_end - The end address of __TEXT segment (all its sections)
+ // eh_frame - The start of __TEXT,__eh_frame
+ // eh_frame_len - The length of __TEXT,__eh_frame
+ // compact_unwind_start - The start of __TEXT,__unwind_info
+ // compact_unwind_len - The length of __TEXT,__unwind_info
+ // arg - The driver-provided generic argument
+ // All addresses are the in-memory, slid, addresses.
+ // If eh_frame or unwind_info are missing, addr and len is returned as 0.
+ int (*find_image_info)(unw_addr_space_t as, unw_word_t ip, unw_word_t *mh,
+ unw_word_t *text_start, unw_word_t *text_end,
+ unw_word_t *eh_frame, unw_word_t *eh_frame_len,
+ unw_word_t *compact_unwind_start,
+ unw_word_t *compact_unwind_len, void *arg);
+
+ // Added to get the start and end address of a function without needing
+ // all of the information (and potential allocation) that the
+ // find_proc_info() call entails.
+ // as - The address space to use
+ // ip - The address libunwind wants to know about
+ // low - The start address of the function at 'ip'
+ // high - The first address past the function at 'ip'
+ // arg - The driver-provided generic argument
+ // If HIGH is unknown, it should be set to 0. All addresses
+ // are the in-memory, slid, addresses.
+ int (*get_proc_bounds)(unw_addr_space_t as, unw_word_t ip,
+ unw_word_t *low, unw_word_t *high, void *arg);
+
+ // Added to support accessing non-word-size memory objects across
+ // platforms. No byte swapping should be done.
+ // as - The address space to use
+ // addr - The starting address to access
+ // extent - The extent of the region to access, in bytes
+ // valp - The local region to be written from / read into
+ // write - non-zero if the data is to be written into the target
+ // rather than read
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*access_raw)(unw_addr_space_t as, unw_word_t addr, unw_word_t extent,
+ uint8_t *valp, int write, void *arg);
+
+ // Added to support identifying registers.
+ // libunwind will interrogate the driver program via this callback to
+ // identify what register numbers it is using; the register names are
+ // used to correlate that the driver program's register numbers with
+ // libunwind's internal register numbers. The driver program should
+ // use its own register numbers when requesting registers with
+ // unw_get_reg() and libunwind will provide the driver program's
+ // register numbers to the access_reg callback function.
+ // as - The address space to use
+ // regnum - The register number
+ // type - Write the register type to this address
+ // For a non-existent register, return UNW_ESUCCESS but
+ // write UNW_NOT_A_REG to type
+ // buf - If non-NULL, the register name is written to this address
+ // buf_len - The size of the buffer provided for the register name
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*reg_info)(unw_addr_space_t as, unw_regnum_t regnum,
+ unw_regtype_t* type, char *bufp, size_t buf_len, void *arg);
+
+ // Added to read a vector register's value from the remote machine.
+ // as - The address space to use
+ // regnum - The register number
+ // valp - The local region to be written from / read into
+ // write - non-zero if the data is to be written into the target
+ // rather than read
+ // arg - The driver-specified generic argument
+ int (*access_vecreg)(unw_addr_space_t as, unw_regnum_t regnum,
+ unw_vecreg_t* valp, int write, void *arg);
+
+ // Added to identify if an unwind cursor is pointing to _sigtramp().
+ // After a _sigtramp we have an entire register set available and we should
+ // return any of the registers requested.
+ // as - The address space to use
+ // ip - The address of the function libunwind is examining
+ // arg - The driver-provided generic argument
+ // This function returns non-zero if ip is in _sigtramp.
+ int (*proc_is_sigtramp) (unw_addr_space_t as, unw_word_t ip, void *arg);
+
+ // Added to identify if an unwind cursor is pointing to a debugger's
+ // inferior function call dummy frame.
+ // The driver program will need to provide the full register set (via the
+ // standard access_reg callback) for the function that was executing
+ // when the inferior function call was made; it will use these register
+ // values and not try to unwind out of the inferior function call dummy
+ // frame.
+ // After a inf func call we have an entire register set available and
+ // we should return any of the registers requested.
+ // as - The address space to use
+ // ip - The address of the function libunwind is examining
+ // sp - The stack pointer value of the frame
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ // This function returns non-zero if ip/sp is an inferior function call
+ // dummy frame.
+ int (*proc_is_inferior_function_call) (unw_addr_space_t as, unw_word_t ip,
+ unw_word_t sp, void *arg);
+
+ // Added to retrieve a register value from a above a debugger's inferior
+ // function call dummy frame. Similar to _sigtramp but the debugger will
+ // have the register context squirreled away in its own memory (or possibly
+ // saved on the stack somewhere).
+ // May be NULL if the program being unwound will not have a debugger
+ // calling functions mid-execution.
+ // as - The address space to use
+ // ip - The pc value for the dummy frame
+ // sp - The stack pointer for the dummy frame
+ // regnum - The register number in the driver program's register
+ // numbering scheme.
+ // valp - Pointer to a word of memory to be read/written
+ // write - Non-zero if libunwind is writing a new value to the reg,
+ // else it is reading the contents of that register.
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*access_reg_inf_func_call)(unw_addr_space_t as, unw_word_t ip,
+ unw_word_t sp, unw_regnum_t regnum,
+ unw_word_t *valp, int write, void *arg);
+
+ // Added to iterate over unknown assembly instructions when analyzing a
+ // function prologue. Needed for ISAs with variable length instructions
+ // (i386, x86_64) or multiple instruction sizes (arm, thumb).
+ // Returns zero if the instruction length was successfully measured.
+ // as - The address space to use
+ // addr - The address of the instruction being measured
+ // length - Set to the length of the instruction
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*instruction_length)(unw_addr_space_t as, unw_word_t addr,
+ int *length, void *arg);
+
+} unw_accessors_t;
+
+extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, void*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern unw_accessors_t* unw_get_accessors(unw_addr_space_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern unw_addr_space_t unw_create_addr_space(unw_accessors_t*, unw_targettype_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern void unw_flush_caches(unw_addr_space_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_set_caching_policy(unw_addr_space_t, unw_caching_policy_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern void unw_destroy_addr_space(unw_addr_space_t asp) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern void unw_set_logging_level(unw_addr_space_t, FILE *, unw_log_level_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+// Should be called when remote unwinding if a bundle in the remote process
+// is unloaded
+extern void unw_image_was_unloaded(unw_addr_space_t, unw_word_t mh) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+// Try to discern where the function's prologue instructions end
+// start - start address of the function, required
+// end - first address beyond the function, or zero if unknown
+// endofprologue - set to the address after the last prologue instruction if successful
+extern int unw_end_of_prologue_setup(unw_cursor_t*, unw_word_t start, unw_word_t end, unw_word_t *endofprologue) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+/*
+ * Dynamic unwinding API
+ * NOT IMPLEMENTED on Mac OS X
+ * extern void _U_dyn_register(unw_dyn_info_t*);
+ * extern void _U_dyn_cancel(unw_dyn_info_t*);
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma mark Register numbers
+
+// architecture independent register numbers
+enum {
+ UNW_REG_IP = -1, // instruction pointer
+ UNW_REG_SP = -2, // stack pointer
+};
+
+
+// 32-bit x86 registers
+enum {
+ UNW_X86_EAX = 0,
+ UNW_X86_ECX = 1,
+ UNW_X86_EDX = 2,
+ UNW_X86_EBX = 3,
+ UNW_X86_EBP = 4,
+ UNW_X86_ESP = 5,
+ UNW_X86_ESI = 6,
+ UNW_X86_EDI = 7
+};
+
+
+// 64-bit x86_64 registers
+enum {
+ UNW_X86_64_RAX = 0,
+ UNW_X86_64_RDX = 1,
+ UNW_X86_64_RCX = 2,
+ UNW_X86_64_RBX = 3,
+ UNW_X86_64_RSI = 4,
+ UNW_X86_64_RDI = 5,
+ UNW_X86_64_RBP = 6,
+ UNW_X86_64_RSP = 7,
+ UNW_X86_64_R8 = 8,
+ UNW_X86_64_R9 = 9,
+ UNW_X86_64_R10 = 10,
+ UNW_X86_64_R11 = 11,
+ UNW_X86_64_R12 = 12,
+ UNW_X86_64_R13 = 13,
+ UNW_X86_64_R14 = 14,
+ UNW_X86_64_R15 = 15
+};
+
+
+// 32-bit ppc register numbers
+enum {
+ UNW_PPC_R0 = 0,
+ UNW_PPC_R1 = 1,
+ UNW_PPC_R2 = 2,
+ UNW_PPC_R3 = 3,
+ UNW_PPC_R4 = 4,
+ UNW_PPC_R5 = 5,
+ UNW_PPC_R6 = 6,
+ UNW_PPC_R7 = 7,
+ UNW_PPC_R8 = 8,
+ UNW_PPC_R9 = 9,
+ UNW_PPC_R10 = 10,
+ UNW_PPC_R11 = 11,
+ UNW_PPC_R12 = 12,
+ UNW_PPC_R13 = 13,
+ UNW_PPC_R14 = 14,
+ UNW_PPC_R15 = 15,
+ UNW_PPC_R16 = 16,
+ UNW_PPC_R17 = 17,
+ UNW_PPC_R18 = 18,
+ UNW_PPC_R19 = 19,
+ UNW_PPC_R20 = 20,
+ UNW_PPC_R21 = 21,
+ UNW_PPC_R22 = 22,
+ UNW_PPC_R23 = 23,
+ UNW_PPC_R24 = 24,
+ UNW_PPC_R25 = 25,
+ UNW_PPC_R26 = 26,
+ UNW_PPC_R27 = 27,
+ UNW_PPC_R28 = 28,
+ UNW_PPC_R29 = 29,
+ UNW_PPC_R30 = 30,
+ UNW_PPC_R31 = 31,
+ UNW_PPC_F0 = 32,
+ UNW_PPC_F1 = 33,
+ UNW_PPC_F2 = 34,
+ UNW_PPC_F3 = 35,
+ UNW_PPC_F4 = 36,
+ UNW_PPC_F5 = 37,
+ UNW_PPC_F6 = 38,
+ UNW_PPC_F7 = 39,
+ UNW_PPC_F8 = 40,
+ UNW_PPC_F9 = 41,
+ UNW_PPC_F10 = 42,
+ UNW_PPC_F11 = 43,
+ UNW_PPC_F12 = 44,
+ UNW_PPC_F13 = 45,
+ UNW_PPC_F14 = 46,
+ UNW_PPC_F15 = 47,
+ UNW_PPC_F16 = 48,
+ UNW_PPC_F17 = 49,
+ UNW_PPC_F18 = 50,
+ UNW_PPC_F19 = 51,
+ UNW_PPC_F20 = 52,
+ UNW_PPC_F21 = 53,
+ UNW_PPC_F22 = 54,
+ UNW_PPC_F23 = 55,
+ UNW_PPC_F24 = 56,
+ UNW_PPC_F25 = 57,
+ UNW_PPC_F26 = 58,
+ UNW_PPC_F27 = 59,
+ UNW_PPC_F28 = 60,
+ UNW_PPC_F29 = 61,
+ UNW_PPC_F30 = 62,
+ UNW_PPC_F31 = 63,
+ UNW_PPC_MQ = 64,
+ UNW_PPC_LR = 65,
+ UNW_PPC_CTR = 66,
+ UNW_PPC_AP = 67,
+ UNW_PPC_CR0 = 68,
+ UNW_PPC_CR1 = 69,
+ UNW_PPC_CR2 = 70,
+ UNW_PPC_CR3 = 71,
+ UNW_PPC_CR4 = 72,
+ UNW_PPC_CR5 = 73,
+ UNW_PPC_CR6 = 74,
+ UNW_PPC_CR7 = 75,
+ UNW_PPC_XER = 76,
+ UNW_PPC_V0 = 77,
+ UNW_PPC_V1 = 78,
+ UNW_PPC_V2 = 79,
+ UNW_PPC_V3 = 80,
+ UNW_PPC_V4 = 81,
+ UNW_PPC_V5 = 82,
+ UNW_PPC_V6 = 83,
+ UNW_PPC_V7 = 84,
+ UNW_PPC_V8 = 85,
+ UNW_PPC_V9 = 86,
+ UNW_PPC_V10 = 87,
+ UNW_PPC_V11 = 88,
+ UNW_PPC_V12 = 89,
+ UNW_PPC_V13 = 90,
+ UNW_PPC_V14 = 91,
+ UNW_PPC_V15 = 92,
+ UNW_PPC_V16 = 93,
+ UNW_PPC_V17 = 94,
+ UNW_PPC_V18 = 95,
+ UNW_PPC_V19 = 96,
+ UNW_PPC_V20 = 97,
+ UNW_PPC_V21 = 98,
+ UNW_PPC_V22 = 99,
+ UNW_PPC_V23 = 100,
+ UNW_PPC_V24 = 101,
+ UNW_PPC_V25 = 102,
+ UNW_PPC_V26 = 103,
+ UNW_PPC_V27 = 104,
+ UNW_PPC_V28 = 105,
+ UNW_PPC_V29 = 106,
+ UNW_PPC_V30 = 107,
+ UNW_PPC_V31 = 108,
+ UNW_PPC_VRSAVE = 109,
+ UNW_PPC_VSCR = 110,
+ UNW_PPC_SPE_ACC = 111,
+ UNW_PPC_SPEFSCR = 112
+
+};
+
+
+}; // namespace lldb_private
+
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h b/lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h
new file mode 100644
index 00000000000..bee2ad578d6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h
@@ -0,0 +1,212 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- compact_unwind_encoding.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __COMPACT_UNWIND_ENCODING__
+#define __COMPACT_UNWIND_ENCODING__
+
+#include <stdint.h>
+
+namespace lldb_private {
+
+//
+// Each final linked mach-o image has an optional __TEXT, __unwind_info section.
+// This section is much smaller and faster to use than the __eh_frame section.
+//
+
+
+
+//
+// Compilers usually emit standard Dwarf FDEs. The linker recognizes standard FDEs and
+// synthesizes a matching compact_unwind_encoding_t and adds it to the __unwind_info table.
+// It is also possible for the compiler to emit __unwind_info entries for functions that
+// have different unwind requirements at different ranges in the function.
+//
+typedef uint32_t compact_unwind_encoding_t;
+
+
+
+//
+// The __unwind_info section is laid out for an efficient two level lookup.
+// The header of the section contains a coarse index that maps function address
+// to the page (4096 byte block) containing the unwind info for that function.
+//
+
+#define UNWIND_SECTION_VERSION 1
+struct unwind_info_section_header
+{
+ uint32_t version; // UNWIND_SECTION_VERSION
+ uint32_t commonEncodingsArraySectionOffset;
+ uint32_t commonEncodingsArrayCount;
+ uint32_t personalityArraySectionOffset;
+ uint32_t personalityArrayCount;
+ uint32_t indexSectionOffset;
+ uint32_t indexCount;
+ // compact_unwind_encoding_t[]
+ // uintptr_t personalities[]
+ // unwind_info_section_header_index_entry[]
+ // unwind_info_section_header_lsda_index_entry[]
+};
+
+struct unwind_info_section_header_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
+ uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
+};
+
+struct unwind_info_section_header_lsda_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t lsdaOffset;
+};
+
+//
+// There are two kinds of second level index pages: regular and compressed.
+// A compressed page can hold up to 1021 entries, but it cannot be used
+// if too many different encoding types are used. The regular page holds
+// 511 entries.
+//
+
+struct unwind_info_regular_second_level_entry
+{
+ uint32_t functionOffset;
+ compact_unwind_encoding_t encoding;
+};
+
+#define UNWIND_SECOND_LEVEL_REGULAR 2
+struct unwind_info_regular_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ // entry array
+};
+
+#define UNWIND_SECOND_LEVEL_COMPRESSED 3
+struct unwind_info_compressed_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ uint16_t encodingsPageOffset;
+ uint16_t encodingsCount;
+ // 32-bit entry array
+ // encodings array
+};
+
+#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
+#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
+
+
+
+// architecture independent bits
+enum {
+ UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
+ UNWIND_HAS_LSDA = 0x40000000,
+ UNWIND_PERSONALITY_MASK = 0x30000000,
+};
+
+
+// x86_64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// rbp based:
+// 15-bits (5*3-bits per reg) register permutation
+// 8-bits for stack offset
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_64_MODE_MASK = 0x0F000000,
+ UNWIND_X86_64_MODE_COMPATIBILITY = 0x00000000,
+ UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
+ UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_64_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_64_REG_NONE = 0,
+ UNWIND_X86_64_REG_RBX = 1,
+ UNWIND_X86_64_REG_R12 = 2,
+ UNWIND_X86_64_REG_R13 = 3,
+ UNWIND_X86_64_REG_R14 = 4,
+ UNWIND_X86_64_REG_R15 = 5,
+ UNWIND_X86_64_REG_RBP = 6,
+};
+
+
+// x86
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// ebp based:
+// 15-bits (5*3-bits per reg) register permutation
+// 8-bits for stack offset
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_MODE_MASK = 0x0F000000,
+ UNWIND_X86_MODE_COMPATIBILITY = 0x00000000,
+ UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
+ UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_REG_NONE = 0,
+ UNWIND_X86_REG_EBX = 1,
+ UNWIND_X86_REG_ECX = 2,
+ UNWIND_X86_REG_EDX = 3,
+ UNWIND_X86_REG_EDI = 4,
+ UNWIND_X86_REG_ESI = 5,
+ UNWIND_X86_REG_EBP = 6,
+};
+
+}; // namespace lldb_private
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h b/lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h
new file mode 100644
index 00000000000..80b9d2881c2
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h
@@ -0,0 +1,213 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- unwind.h ------------------------------------------------*- 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 libuwind
+//
+// Source compatible with Level 1 Base ABI documented at:
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __UNWIND_H__
+#define __UNWIND_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <Availability.h>
+
+namespace lldb_private {
+
+typedef enum {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+typedef enum {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16 // gcc extension to C++ ABI
+} _Unwind_Action;
+
+
+struct _Unwind_Context; // opaque
+struct _Unwind_Exception; // forward declaration
+
+struct _Unwind_Exception {
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc);
+ uintptr_t private_1; // non-zero means forced unwind
+ uintptr_t private_2; // holds sp that phase1 found for phase2 to use
+};
+
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context,
+ void* stop_parameter );
+
+
+typedef _Unwind_Reason_Code (*__personality_routine)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context);
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// The following are the base functions documented by the C++ ABI
+//
+#if __arm__
+ extern _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object);
+ extern void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object);
+#else
+ extern _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object);
+ extern void _Unwind_Resume(struct _Unwind_Exception* exception_object);
+#endif
+extern void _Unwind_DeleteException(struct _Unwind_Exception* exception_object);
+extern uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index);
+extern void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value);
+extern uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
+extern void _Unwind_SetIP(struct _Unwind_Context*, uintptr_t new_value);
+extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context);
+extern uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context);
+#if __arm__
+ extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
+#else
+ extern _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
+#endif
+
+#if __arm__
+ typedef struct _Unwind_FunctionContext* _Unwind_FunctionContext_t;
+ extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
+ extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
+#endif
+
+//
+// The following are semi-suppoted extensions to the C++ ABI
+//
+
+
+//
+// called by __cxa_rethrow().
+//
+#if __arm__
+ extern _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
+#else
+ extern _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
+#endif
+
+
+//
+// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
+// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
+// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
+//
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
+extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
+
+
+//
+// _Unwind_GetCFA is a gcc extension that can be called from within a personality
+// handler to get the CFA (stack pointer before call) of current frame.
+//
+extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context*);
+
+
+//
+// _Unwind_GetIPInfo is a gcc extension that can be called from within a personality
+// handler. Similar to _Unwind_GetIP() but also returns in *ipBefore a non-zero
+// value if the instruction pointer is at or before the instruction causing
+// the unwind. Normally, in a function call, the IP returned is the return address
+// which is after the call instruction and may be past the end of the function
+// containing the call instruction.
+//
+extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore);
+
+
+//
+// __register_frame() is used with dynamically generated code to register the FDE
+// for a generated (JIT) code. The FDE must use pc-rel addressing to point to its
+// function and optional LSDA. __register_frame() has existed in all versions of
+// Mac OS X, but in 10.4 and 10.5 it was buggy and did not actually register the
+// FDE with the unwinder. In 10.6 and later it does register properly.
+//
+extern void __register_frame(const void* fde);
+extern void __deregister_frame(const void* fde);
+
+
+//
+// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
+// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind info"
+// which the runtime uses in preference to dwarf unwind info. This function
+// will only work if the target function has an FDE but no compact unwind info.
+//
+struct dwarf_eh_bases
+{
+ uintptr_t tbase;
+ uintptr_t dbase;
+ uintptr_t func;
+};
+extern const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases*);
+
+
+//
+// This function attempts to find the start (address of first instruction) of
+// a function given an address inside the function. It only works if the function
+// has an FDE (dwarf unwind info).
+// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
+// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
+extern void* _Unwind_FindEnclosingFunction(void* pc);
+
+
+// Mac OS X does not support text-rel and data-rel addressing so these functions are unimplemented
+extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
+extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
+
+
+
+// Mac OS X 10.4 and 10.5 had implementations of these functions in libgcc_s.dylib,
+// but they never worked. These functions are no longer available.
+extern void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db) __attribute__((unavailable));
+extern void __register_frame_info(const void* fde, void* ob) __attribute__((unavailable));
+extern void __register_frame_info_table_bases(const void* fde, void* ob,void* tb, void* db) __attribute__((unavailable));
+extern void __register_frame_info_table(const void* fde, void* ob) __attribute__((unavailable));
+extern void __register_frame_table(const void* fde) __attribute__((unavailable));
+extern void* __deregister_frame_info(const void* fde) __attribute__((unavailable));
+extern void* __deregister_frame_info_bases(const void* fde) __attribute__((unavailable));
+
+
+#ifdef __cplusplus
+}
+#endif
+
+}; // namespace lldb_private
+
+#endif // __UNWIND_H__
+
+
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__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp
new file mode 100644
index 00000000000..d19d7aea50f
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp
@@ -0,0 +1,115 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- ArchDefaultUnwinder.hpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Unwind a stack frame using nothing but the default conventions on
+// this architecture.
+
+#ifndef __ARCH_DEFAULT_UNWINDER_HPP
+#define __ARCH_DEFAULT_UNWINDER_HPP
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "RemoteRegisterMap.hpp"
+#include "RemoteProcInfo.hpp"
+
+namespace lldb_private
+{
+
+// As a last ditch attempt to unwind a stack frame, unwind by the
+// architecture's typical conventions. We try compact unwind, eh frame CFI,
+// and then assembly profiling if we have function bounds -- but if we're
+// looking at an address with no function bounds or unwind info, make a best
+// guess at how to get out.
+
+// In practice, this is usually hit when we try to step out of start() in a
+// stripped application binary, we've jumped to 0x0, or we're in jitted code
+// in the heap.
+
+template <typename A, typename R>
+int stepByArchitectureDefault_x86 (A& addressSpace, R& registers,
+ uint64_t pc, int wordsize) {
+ R newRegisters(registers);
+ RemoteRegisterMap *rmap = addressSpace.getRemoteProcInfo()->getRegisterMap();
+ int frame_reg = rmap->unwind_regno_for_frame_pointer();
+ int stack_reg = rmap->unwind_regno_for_stack_pointer();
+ int err;
+
+ /* If the pc is 0x0 either we call'ed 0 (went thorugh a null function
+ pointer) or this is a thread in the middle of being created that has
+ no stack at all.
+ For the call-0x0 case, we know how to unwind that - the pc is at
+ the stack pointer.
+
+ Otherwise follow the usual convention of trusting that RBP/EBP has the
+ start of the stack frame and we can find the caller's pc based on
+ that. */
+
+ uint64_t newpc, newframeptr;
+ newpc = 0;
+ newframeptr = -1;
+ if (pc == 0) {
+ uint64_t oldsp = registers.getRegister(stack_reg);
+ err = 0;
+ if (oldsp != 0) {
+ newpc = addressSpace.getP(registers.getRegister(stack_reg), err);
+ if (err != 0)
+ return UNW_EUNSPEC;
+ newRegisters.setIP (newpc);
+ newRegisters.setRegister (stack_reg, registers.getRegister(stack_reg) +
+ wordsize);
+ }
+ }
+ else {
+ newpc = addressSpace.getP(registers.getRegister(frame_reg) +
+ wordsize, err);
+ if (err != 0)
+ return UNW_EUNSPEC;
+
+ newRegisters.setIP (newpc);
+ newframeptr = addressSpace.getP(registers.getRegister(frame_reg),
+ err);
+ if (err != 0)
+ return UNW_EUNSPEC;
+
+ newRegisters.setRegister (frame_reg, newframeptr);
+ newRegisters.setRegister (stack_reg, registers.getRegister(frame_reg) +
+ (wordsize * 2));
+ }
+ registers = newRegisters;
+ if (newpc == 0 || newframeptr == 0)
+ return UNW_STEP_END;
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int stepByArchitectureDefault (A& addressSpace, Registers_x86_64 &registers,
+ uint64_t pc) {
+ return stepByArchitectureDefault_x86 (addressSpace, registers, pc, 8);
+}
+
+template <typename A>
+int stepByArchitectureDefault (A& addressSpace, Registers_x86& registers,
+ uint64_t pc) {
+ return stepByArchitectureDefault_x86 (addressSpace, registers, pc, 4);
+}
+
+template <typename A>
+int stepByArchitectureDefault (A& addressSpace, Registers_ppc& registers,
+ uint64_t pc) {
+ ABORT("Remote unwinding not supported for ppc.");
+ return UNW_EUNSPEC;
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif // __ARCH_DEFAULT_UNWINDER_HPP
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
new file mode 100644
index 00000000000..1e695d5e4f0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
@@ -0,0 +1,147 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- AssemblyInstructions.hpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ASSEMBLY_INSTRUCTIONS_HPP
+#define __ASSEMBLY_INSTRUCTIONS_HPP
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <map>
+
+#include "libunwind.h"
+#include "AssemblyParser.hpp"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "RemoteUnwindProfile.h"
+
+namespace lldb_private
+{
+
+// A debug function to dump the contents of an RemoteUnwindProfile to
+// stdout in a human readable form.
+
+template <typename A, typename R>
+void printProfile (A& addressSpace, uint64_t pc, RemoteUnwindProfile* profile, R& registers) {
+ RemoteProcInfo *procinfo = addressSpace.getRemoteProcInfo();
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap();
+
+ procinfo->logDebug ("Print profile: given pc of 0x%llx, profile has range 0x%llx - 0x%llx", pc, profile->fStart, profile->fEnd);
+ procinfo->logDebug ("CFA locations:");
+ std::map<uint64_t, RemoteUnwindProfile::CFALocation>::iterator i;
+ for (i = profile->cfa.begin(); i != profile->cfa.end(); ++i) {
+ procinfo->logDebug (" as of 0x%llx cfa is based off of reg %d (%s) offset %d", i->first, i->second.regno, regmap->unwind_regno_to_name(i->second.regno), i->second.offset);
+ }
+ procinfo->logDebug ("Caller's saved IP is at %d bytes offset from the cfa", (int)profile->returnAddress.value);
+ procinfo->logDebug ("Register saves:");
+ std::map<uint64_t, std::vector<RemoteUnwindProfile::SavedReg> >::iterator j;
+ for (j = profile->saved_registers.begin(); j != profile->saved_registers.end(); ++j) {
+ char *tbuf1, *tbuf2, *tbuf3;
+ asprintf (&tbuf1, " at pc 0x%llx there are %d registers saved ", j->first, (int) j->second.size());
+ std::vector<RemoteUnwindProfile::SavedReg>::iterator k;
+ for (k = j->second.begin(); k != j->second.end(); ++k) {
+ if (k->location == RemoteUnwindProfile::kRegisterOffsetFromCFA) {
+ asprintf (&tbuf2, "[reg %d (%s) is %d bytes from cfa] ", k->regno, regmap->unwind_regno_to_name(k->regno), (int) k->value);
+ int newlen = strlen (tbuf1) + strlen (tbuf2) + 1;
+ tbuf3 = (char *) malloc (newlen);
+ strcpy (tbuf3, tbuf1);
+ strcat (tbuf3, tbuf2);
+ free (tbuf1);
+ free (tbuf2);
+ tbuf1 = tbuf3;
+ }
+ if (k->location == RemoteUnwindProfile::kRegisterIsCFA) {
+ asprintf (&tbuf2, "[reg %d (%s) is the same as the cfa] ", k->regno, regmap->unwind_regno_to_name(k->regno));
+ int newlen = strlen (tbuf1) + strlen (tbuf2) + 1;
+ tbuf3 = (char *) malloc (newlen);
+ strcpy (tbuf3, tbuf1);
+ strcat (tbuf3, tbuf2);
+ free (tbuf1);
+ free (tbuf2);
+ tbuf1 = tbuf3;
+ }
+ }
+ procinfo->logDebug ("%s", tbuf1);
+ free (tbuf1);
+ }
+}
+
+template <typename A, typename R>
+int stepWithAssembly (A& addressSpace, uint64_t pc, RemoteUnwindProfile* profile, R& registers) {
+ R newRegisters(registers);
+ RemoteProcInfo *procinfo = addressSpace.getRemoteProcInfo();
+ if (pc > profile->fEnd)
+ ABORT("stepWithAssembly called with pc not in RemoteUnwindProfile's bounds");
+
+ if (procinfo && (procinfo->getDebugLoggingLevel() & UNW_LOG_LEVEL_DEBUG))
+ printProfile (addressSpace, pc, profile, registers);
+
+ std::map<uint64_t, RemoteUnwindProfile::CFALocation>::iterator i = profile->cfa.lower_bound (pc);
+ if (i == profile->cfa.begin() && i == profile->cfa.end())
+ return UNW_EINVAL;
+ if (i == profile->cfa.end()) {
+ --i;
+ } else {
+ if (i != profile->cfa.begin() && i->first != pc)
+ --i;
+ }
+
+ uint64_t cfa = registers.getRegister (i->second.regno) + i->second.offset;
+
+ std::map<uint64_t, std::vector<RemoteUnwindProfile::SavedReg> >::iterator j;
+
+ for (j = profile->saved_registers.begin(); j != profile->saved_registers.end() && j->first <= pc; ++j) {
+ std::vector<RemoteUnwindProfile::SavedReg>::iterator k = j->second.begin();
+ for (; k != j->second.end(); ++k) {
+ RemoteUnwindProfile::SavedReg sr = *k;
+ if (sr.type == RemoteUnwindProfile::kGeneralPurposeRegister) {
+ uint64_t result;
+ int err = 0;
+ switch (sr.location) {
+ case RemoteUnwindProfile::kRegisterOffsetFromCFA:
+ result = addressSpace.getP(cfa + sr.value, err);
+ break;
+ case RemoteUnwindProfile::kRegisterIsCFA:
+ result = cfa;
+ break;
+ default:
+ ABORT("Unknown saved register location in stepWithAssembly.");
+ }
+ // If we failed to read remote memory, stop unwinding.
+ if (err)
+ return UNW_STEP_END;
+ newRegisters.setRegister (sr.regno, result);
+ }
+ }
+ }
+ newRegisters.setSP(cfa);
+ uint64_t ip = addressSpace.getP(cfa + profile->returnAddress.value);
+ if (ip == 0)
+ return UNW_STEP_END;
+ newRegisters.setIP(ip);
+ registers = newRegisters;
+ return UNW_STEP_SUCCESS;
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif //ASSEMBLY_INSTRUCTIONS_HPP
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp
new file mode 100644
index 00000000000..b34f93f50c6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp
@@ -0,0 +1,409 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- AssemblyParser.hpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Disassemble the prologue instructions in functions, create a profile
+// of stack movements and register saves performed therein.
+
+#ifndef __ASSEMBLY_PARSER_HPP
+#define __ASSEMBLY_PARSER_HPP
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <map>
+#include <vector>
+
+#include "libunwind.h"
+#include "RemoteProcInfo.hpp"
+#include "Registers.hpp"
+#include "FileAbstraction.hpp"
+#include "AddressSpace.hpp"
+#include "RemoteUnwindProfile.h"
+
+namespace lldb_private
+{
+
+// Analyze the instructions in an x86_64/i386 function prologue, fill out an RemoteUnwindProfile.
+
+class AssemblyParse_x86 {
+public:
+ AssemblyParse_x86 (RemoteProcInfo& procinfo, unw_accessors_t *acc, unw_addr_space_t as, void *arg) : fArg(arg), fAccessors(acc), fAs(as), fRemoteProcInfo(procinfo) {
+ fRegisterMap = fRemoteProcInfo.getRegisterMap();
+ if (fRemoteProcInfo.getTargetArch() == UNW_TARGET_X86_64) {
+ fStackPointerRegnum = UNW_X86_64_RSP;
+ fFramePointerRegnum = UNW_X86_64_RBP;
+ fWordSize = 8;
+ } else {
+ fStackPointerRegnum = UNW_X86_ESP;
+ fFramePointerRegnum = UNW_X86_EBP;
+ fWordSize = 4;
+ }
+ }
+
+ uint32_t extract_4_LE (uint8_t *b) {
+ uint32_t v = 0;
+ for (int i = 3; i >= 0; i--)
+ v = (v << 8) | b[i];
+ return v;
+ }
+
+ bool push_rbp_pattern_p ();
+ bool push_0_pattern_p ();
+ bool mov_rsp_rbp_pattern_p ();
+ bool sub_rsp_pattern_p (int *amount);
+ bool push_reg_p (int *regno);
+ bool mov_reg_to_local_stack_frame_p (int *regno, int *rbp_offset);
+ bool ret_pattern_p ();
+ bool profileFunction (uint64_t start, uint64_t end, RemoteUnwindProfile& profile);
+
+private:
+
+ void *fArg;
+ uint8_t* fCurInsnByteBuf;
+ int fCurInsnSize;
+ RemoteProcInfo& fRemoteProcInfo;
+ RemoteRegisterMap *fRegisterMap;
+ unw_accessors_t *fAccessors;
+ unw_addr_space_t fAs;
+ int fWordSize;
+ int fStackPointerRegnum;
+ int fFramePointerRegnum;
+};
+
+// Macro to detect if this is a REX mode prefix byte.
+#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
+
+// The high bit which should be added to the source register number (the "R" bit)
+#define REX_W_SRCREG(opcode) (((opcode) & 0x4) >> 2)
+
+// The high bit which should be added to the destination register number (the "B" bit)
+#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
+
+// pushq %rbp [0x55]
+bool AssemblyParse_x86::push_rbp_pattern_p () {
+ uint8_t *p = fCurInsnByteBuf;
+ if (*p == 0x55)
+ return true;
+ return false;
+}
+
+// pushq $0 ; the first instruction in start() [0x6a 0x00]
+bool AssemblyParse_x86::push_0_pattern_p ()
+{
+ uint8_t *p = fCurInsnByteBuf;
+ if (*p == 0x6a && *(p + 1) == 0x0)
+ return true;
+ return false;
+}
+
+// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
+// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
+bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () {
+ uint8_t *p = fCurInsnByteBuf;
+ if (fWordSize == 8 && *p == 0x48)
+ p++;
+ if (*(p) == 0x8b && *(p + 1) == 0xec)
+ return true;
+ if (*(p) == 0x89 && *(p + 1) == 0xe5)
+ return true;
+ return false;
+}
+
+// subq $0x20, %rsp
+bool AssemblyParse_x86::sub_rsp_pattern_p (int *amount) {
+ uint8_t *p = fCurInsnByteBuf;
+ if (fWordSize == 8 && *p == 0x48)
+ p++;
+ // 8-bit immediate operand
+ if (*p == 0x83 && *(p + 1) == 0xec) {
+ *amount = (int8_t) *(p + 2);
+ return true;
+ }
+ // 32-bit immediate operand
+ if (*p == 0x81 && *(p + 1) == 0xec) {
+ *amount = (int32_t) extract_4_LE (p + 2);
+ return true;
+ }
+ // Not handled: [0x83 0xc4] for imm8 with neg values
+ // [0x81 0xc4] for imm32 with neg values
+ return false;
+}
+
+// pushq %rbx
+// pushl $ebx
+bool AssemblyParse_x86::push_reg_p (int *regno) {
+ uint8_t *p = fCurInsnByteBuf;
+ int regno_prefix_bit = 0;
+ // If we have a rex prefix byte, check to see if a B bit is set
+ if (fWordSize == 8 && *p == 0x41) {
+ regno_prefix_bit = 1 << 3;
+ p++;
+ }
+ if (*p >= 0x50 && *p <= 0x57) {
+ int r = (*p - 0x50) | regno_prefix_bit;
+ if (fRegisterMap->machine_regno_to_unwind_regno (r, *regno) == true) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Look for an instruction sequence storing a nonvolatile register
+// on to the stack frame.
+
+// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
+// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4]
+bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int *regno, int *rbp_offset) {
+ uint8_t *p = fCurInsnByteBuf;
+ int src_reg_prefix_bit = 0;
+ int target_reg_prefix_bit = 0;
+
+ if (fWordSize == 8 && REX_W_PREFIX_P (*p)) {
+ src_reg_prefix_bit = REX_W_SRCREG (*p) << 3;
+ target_reg_prefix_bit = REX_W_DSTREG (*p) << 3;
+ if (target_reg_prefix_bit == 1) {
+ // rbp/ebp don't need a prefix bit - we know this isn't the
+ // reg we care about.
+ return false;
+ }
+ p++;
+ }
+
+ if (*p == 0x89) {
+ /* Mask off the 3-5 bits which indicate the destination register
+ if this is a ModR/M byte. */
+ int opcode_destreg_masked_out = *(p + 1) & (~0x38);
+
+ /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
+ and three bits between them, e.g. 01nnn101
+ We're looking for a destination of ebp-disp8 or ebp-disp32. */
+ int immsize;
+ if (opcode_destreg_masked_out == 0x45)
+ immsize = 2;
+ else if (opcode_destreg_masked_out == 0x85)
+ immsize = 4;
+ else
+ return false;
+
+ int offset = 0;
+ if (immsize == 2)
+ offset = (int8_t) *(p + 2);
+ if (immsize == 4)
+ offset = (uint32_t) extract_4_LE (p + 2);
+ if (offset > 0)
+ return false;
+
+ int savedreg = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
+ if (fRegisterMap->machine_regno_to_unwind_regno (savedreg, *regno) == true) {
+ *rbp_offset = offset > 0 ? offset : -offset;
+ return true;
+ }
+ }
+ return false;
+}
+
+// ret [0xc9] or [0xc2 imm8] or [0xca imm8]
+bool AssemblyParse_x86::ret_pattern_p () {
+ uint8_t *p = fCurInsnByteBuf;
+ if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)
+ return true;
+ return false;
+}
+
+bool AssemblyParse_x86::profileFunction (uint64_t start, uint64_t end, RemoteUnwindProfile& profile) {
+ if (start == -1 || end == 0)
+ return false;
+
+ profile.fStart = start;
+ profile.fEnd = end;
+ profile.fRegSizes[RemoteUnwindProfile::kGeneralPurposeRegister] = fWordSize;
+ profile.fRegSizes[RemoteUnwindProfile::kFloatingPointRegister] = 8;
+ profile.fRegSizes[RemoteUnwindProfile::kVectorRegister] = 16;
+
+ // On function entry, the CFA is rsp+fWordSize
+
+ RemoteUnwindProfile::CFALocation initial_cfaloc;
+ initial_cfaloc.regno = fStackPointerRegnum;
+ initial_cfaloc.offset = fWordSize;
+ profile.cfa[start] = initial_cfaloc;
+
+ // The return address is at CFA - fWordSize
+ // CFA doesn't change value during the lifetime of the function (hence "C")
+ // so the returnAddress is the same for the duration of the function.
+
+ profile.returnAddress.regno = 0;
+ profile.returnAddress.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ profile.returnAddress.value = -fWordSize;
+ profile.returnAddress.adj = 0;
+ profile.returnAddress.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+
+ // The caller's rsp has the same value as the CFA at all points during
+ // this function's lifetime.
+
+ RemoteUnwindProfile::SavedReg rsp_loc;
+ rsp_loc.regno = fStackPointerRegnum;
+ rsp_loc.location = RemoteUnwindProfile::kRegisterIsCFA;
+ rsp_loc.value = 0;
+ rsp_loc.adj = 0;
+ rsp_loc.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[start].push_back(rsp_loc);
+ profile.fRegistersSaved[fStackPointerRegnum] = 1;
+
+ int non_prologue_insn_count = 0;
+ int insn_count = 0;
+ uint64_t cur_addr = start;
+ uint64_t first_insn_past_prologue = start;
+ int push_rbp_seen = 0;
+ int current_cfa_register = fStackPointerRegnum;
+ int sp_adjustments = 0;
+
+ while (cur_addr < end && non_prologue_insn_count < 10)
+ {
+ int offset, regno;
+ uint64_t next_addr;
+ insn_count++;
+ int is_prologue_insn = 0;
+
+ if (fAccessors->instruction_length (fAs, cur_addr, &fCurInsnSize, fArg) != 0) {
+ /* An error parsing the instruction; stop scanning. */
+ break;
+ }
+ fCurInsnByteBuf = (uint8_t *) malloc (fCurInsnSize);
+ if (fRemoteProcInfo.getBytes (cur_addr, fCurInsnSize, fCurInsnByteBuf, fArg) == 0)
+ return false;
+ next_addr = cur_addr + fCurInsnSize;
+
+ // start () opens with a 'push $0x0' which is in the saved ip slot on the stack -
+ // so we know to stop backtracing here. We need to ignore this instruction.
+ if (push_0_pattern_p () && push_rbp_seen == 0 && insn_count == 1)
+ {
+ cur_addr = next_addr;
+ first_insn_past_prologue = next_addr;
+ continue;
+ }
+
+ if (push_rbp_pattern_p () && push_rbp_seen == 0)
+ {
+ if (current_cfa_register == fStackPointerRegnum) {
+ sp_adjustments -= fWordSize;
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fStackPointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ }
+
+ RemoteUnwindProfile::SavedReg sreg;
+ sreg.regno = fFramePointerRegnum;
+ sreg.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ sreg.value = sp_adjustments - fWordSize;
+ sreg.adj = 0;
+ sreg.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[next_addr].push_back(sreg);
+
+ push_rbp_seen = 1;
+ profile.fRegistersSaved[fFramePointerRegnum] = 1;
+ is_prologue_insn = 1;
+ goto next_iteration;
+ }
+ if (mov_rsp_rbp_pattern_p ()) {
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fFramePointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ current_cfa_register = fFramePointerRegnum;
+ is_prologue_insn = 1;
+ goto next_iteration;
+ }
+ if (ret_pattern_p ()) {
+ break;
+ }
+ if (sub_rsp_pattern_p (&offset)) {
+ sp_adjustments -= offset;
+ if (current_cfa_register == fStackPointerRegnum) {
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fStackPointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ }
+ is_prologue_insn = 1;
+ }
+ if (push_reg_p (&regno)) {
+ sp_adjustments -= fWordSize;
+ if (current_cfa_register == fStackPointerRegnum) {
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fStackPointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ is_prologue_insn = 1;
+ }
+ if (fRegisterMap->nonvolatile_reg_p (regno) && profile.fRegistersSaved[regno] == 0) {
+ RemoteUnwindProfile::SavedReg sreg;
+ sreg.regno = regno;
+ sreg.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ sreg.value = sp_adjustments - fWordSize;
+ sreg.adj = 0;
+ sreg.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[next_addr].push_back(sreg);
+ profile.fRegistersSaved[regno] = 1;
+ is_prologue_insn = 1;
+ }
+ }
+ if (mov_reg_to_local_stack_frame_p (&regno, &offset)
+ && fRegisterMap->nonvolatile_reg_p (regno)
+ && profile.fRegistersSaved[regno] == 0) {
+ RemoteUnwindProfile::SavedReg sreg;
+ sreg.regno = regno;
+ sreg.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ sreg.value = offset - fWordSize;
+ sreg.adj = 0;
+ sreg.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[next_addr].push_back(sreg);
+ profile.fRegistersSaved[regno] = 1;
+ is_prologue_insn = 1;
+ }
+next_iteration:
+ if (is_prologue_insn) {
+ first_insn_past_prologue = next_addr;
+ non_prologue_insn_count = 0;
+ }
+ cur_addr = next_addr;
+ non_prologue_insn_count++;
+ }
+ profile.fFirstInsnPastPrologue = first_insn_past_prologue;
+ return true;
+}
+
+
+
+
+bool AssemblyParse (RemoteProcInfo *procinfo, unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, RemoteUnwindProfile &profile, void *arg) {
+ if (procinfo->getTargetArch() == UNW_TARGET_X86_64 || procinfo->getTargetArch() == UNW_TARGET_I386) {
+ AssemblyParse_x86 parser(*procinfo, acc, as, arg);
+ return parser.profileFunction (start, end, profile);
+ } else {
+ ABORT("Only x86_64 and i386 assembly parsing supported at this time");
+ return false;
+ }
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif //ASSEMBLY_PARSER_HPP
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
new file mode 100644
index 00000000000..dda2308ada6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
@@ -0,0 +1,1019 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- CompactUnwinder.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 __COMPACT_UNWINDER_HPP__
+#define __COMPACT_UNWINDER_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+
+
+
+#define EXTRACT_BITS(value, mask) \
+ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+#define SUPPORT_OLD_BINARIES 0
+
+namespace lldb_private {
+
+
+
+///
+/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka unwind) by
+/// modifying a Registers_x86 register set
+///
+template <typename A>
+class CompactUnwinder_x86
+{
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t info, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A& addressSpace, Registers_x86& registers);
+ static void framelessUnwind(A& addressSpace, typename A::pint_t returnAddressLocation, Registers_x86& registers);
+ static int stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+ static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers, bool indirectStackSize);
+#if SUPPORT_OLD_BINARIES
+ static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+#endif
+};
+
+
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ switch ( compactEncoding & UNWIND_X86_MODE_MASK ) {
+#if SUPPORT_OLD_BINARIES
+ case UNWIND_X86_MODE_COMPATIBILITY:
+ return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers);
+#endif
+ case UNWIND_X86_MODE_EBP_FRAME:
+ return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, addressSpace, registers);
+ case UNWIND_X86_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false);
+ case UNWIND_X86_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true);
+ }
+ ABORT("invalid compact unwind encoding");
+}
+
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A& addressSpace, Registers_x86& registers)
+{
+ uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+
+ uint64_t savedRegisters = registers.getEBP() - 4*savedRegistersOffset;
+ for (int i=0; i < 5; ++i) {
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for EBP frame, encoding=%08X for function starting at 0x%X\n", compactEncoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding, uint32_t functionStart,
+ A& addressSpace, Registers_x86& registers, bool indirectStackSize)
+{
+ uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded*4;
+ if ( indirectStackSize ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart+stackSizeEncoded);
+ stackSize = subl + 4*stackAdjust;
+ }
+ // decompress permutation
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint64_t savedRegisters = registers.getSP() + stackSize - 4 - 4*regCount;
+ for (uint32_t i=0; i < regCount; ++i) {
+ switch ( registersSaved[i] ) {
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EBP:
+ registers.setEBP(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%X\n", encoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+#if SUPPORT_OLD_BINARIES
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ typename A::pint_t savedRegisters;
+ uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_SIZE);
+ uint32_t stackSize;
+ uint32_t stackAdjust;
+ switch (compactEncoding & UNWIND_X86_CASE_MASK ) {
+ case UNWIND_X86_UNWIND_INFO_UNSPECIFIED:
+ return UNW_ENOINFO;
+
+ case UNWIND_X86_EBP_FRAME_NO_REGS:
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_ESI:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EDI:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_ESI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_ESI_EDI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_ESI_EDI:
+ savedRegisters = registers.getEBP() - 12;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_EDI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_NO_REGS:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*0;
+ framelessUnwind(addressSpace, savedRegisters+4*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI_EDI_EBP:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ registers.setEBP(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI_EDI_EBP:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ registers.setEBP(addressSpace.get32(savedRegisters+12));
+ framelessUnwind(addressSpace, savedRegisters+4*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_NO_REGS:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*0;
+ framelessUnwind(addressSpace, savedRegisters+4*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ return UNW_STEP_SUCCESS;
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+
+ case UNWIND_X86_IND_STK_EBX_ESI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI_EDI_EBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ registers.setEBP(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX_ESI_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX_ESI_EDI_EBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ registers.setEBP(addressSpace.get32(savedRegisters+12));
+ framelessUnwind(addressSpace, savedRegisters+4*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ default:
+ DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%X\n",
+ compactEncoding & UNWIND_X86_CASE_MASK, functionStart);
+ ABORT("unknown compact unwind encoding");
+ }
+ return UNW_EINVAL;
+}
+#endif // SUPPORT_OLD_BINARIES
+
+
+
+template <typename A>
+void CompactUnwinder_x86<A>::frameUnwind(A& addressSpace, Registers_x86& registers)
+{
+ typename A::pint_t bp = registers.getEBP();
+ // ebp points to old ebp
+ registers.setEBP(addressSpace.get32(bp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP(bp+8);
+ // pop return address into eip
+ registers.setIP(addressSpace.get32(bp+4));
+}
+
+template <typename A>
+void CompactUnwinder_x86<A>::framelessUnwind(A& addressSpace, typename A::pint_t returnAddressLocation, Registers_x86& registers)
+{
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get32(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(returnAddressLocation+4);
+}
+
+
+
+
+
+///
+/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka unwind) by
+/// modifying a Registers_x86_64 register set
+///
+template <typename A>
+class CompactUnwinder_x86_64
+{
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A& addressSpace, Registers_x86_64& registers);
+ static void framelessUnwind(A& addressSpace, uint64_t returnAddressLocation, Registers_x86_64& registers);
+ static int stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+ static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers, bool indirectStackSize);
+#if SUPPORT_OLD_BINARIES
+ static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+#endif
+};
+
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ switch ( compactEncoding & UNWIND_X86_64_MODE_MASK ) {
+#if SUPPORT_OLD_BINARIES
+ case UNWIND_X86_64_MODE_COMPATIBILITY:
+ return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers);
+#endif
+ case UNWIND_X86_64_MODE_RBP_FRAME:
+ return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, addressSpace, registers);
+ case UNWIND_X86_64_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false);
+ case UNWIND_X86_64_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true);
+ }
+ ABORT("invalid compact unwind encoding");
+}
+
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A& addressSpace, Registers_x86_64& registers)
+{
+ uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+
+ uint64_t savedRegisters = registers.getRBP() - 8*savedRegistersOffset;
+ for (int i=0; i < 5; ++i) {
+ int readerr = 0;
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_64_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters, readerr));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for RBP frame, encoding=%08X for function starting at 0x%llX\n", compactEncoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ // Error reading memory while doing a remote unwind?
+ if (readerr)
+ return UNW_STEP_END;
+
+ savedRegisters += 8;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding, uint64_t functionStart,
+ A& addressSpace, Registers_x86_64& registers, bool indirectStackSize)
+{
+ uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded*8;
+ if ( indirectStackSize ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart+stackSizeEncoded);
+ stackSize = subl + 8*stackAdjust;
+ }
+ // decompress permutation
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8*regCount;
+ for (uint32_t i=0; i < regCount; ++i) {
+ switch ( registersSaved[i] ) {
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ registers.setRBP(addressSpace.get64(savedRegisters));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%llX\n", encoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 8;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+#if SUPPORT_OLD_BINARIES
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers)
+{
+ uint64_t savedRegisters;
+ uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_SIZE);
+ uint64_t stackSize;
+ uint32_t stackAdjust;
+
+ switch (compactEncoding & UNWIND_X86_64_CASE_MASK ) {
+ case UNWIND_X86_64_UNWIND_INFO_UNSPECIFIED:
+ return UNW_ENOINFO;
+
+ case UNWIND_X86_64_RBP_FRAME_NO_REGS:
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX:
+ savedRegisters = registers.getRBP() - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12:
+ savedRegisters = registers.getRBP() - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13:
+ savedRegisters = registers.getRBP() - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14:
+ savedRegisters = registers.getRBP() - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14_R15:
+ savedRegisters = registers.getRBP() - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_NO_REGS:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*0;
+ framelessUnwind(addressSpace, savedRegisters+8*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+8*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14_R15:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14_R15:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*6;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ registers.setR15(addressSpace.get64(savedRegisters+40));
+ framelessUnwind(addressSpace, savedRegisters+8*6, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_NO_REGS:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*0;
+ framelessUnwind(addressSpace, savedRegisters+8*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+8*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14_R15:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14_R15:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*6;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ registers.setR15(addressSpace.get64(savedRegisters+40));
+ framelessUnwind(addressSpace, savedRegisters+8*6, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ default:
+ DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%llX\n",
+ compactEncoding & UNWIND_X86_64_CASE_MASK, functionStart);
+ ABORT("unknown compact unwind encoding");
+ }
+ return UNW_EINVAL;
+}
+#endif // SUPPORT_OLD_BINARIES
+
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::frameUnwind(A& addressSpace, Registers_x86_64& registers)
+{
+ uint64_t rbp = registers.getRBP();
+ // ebp points to old ebp
+ registers.setRBP(addressSpace.get64(rbp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP(rbp+16);
+ // pop return address into eip
+ registers.setIP(addressSpace.get64(rbp+8));
+}
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::framelessUnwind(A& addressSpace, uint64_t returnAddressLocation, Registers_x86_64& registers)
+{
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get64(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(returnAddressLocation+8);
+}
+
+
+}; // namespace lldb_private
+
+
+
+#endif // __COMPACT_UNWINDER_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp
new file mode 100644
index 00000000000..589c30b50b9
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp
@@ -0,0 +1,1686 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- DwarfInstructions.hpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_INSTRUCTIONS_HPP__
+#define __DWARF_INSTRUCTIONS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <vector>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "dwarf2.h"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfParser.hpp"
+#include "InternalMacros.h"
+//#include "CompactUnwinder.hpp"
+
+#define EXTRACT_BITS(value, mask) \
+ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+#define CFI_INVALID_ADDRESS ((pint_t)(-1))
+
+namespace lldb_private {
+
+///
+/// Used by linker when parsing __eh_frame section
+///
+template <typename A>
+struct CFI_Reference {
+ typedef typename A::pint_t pint_t;
+ uint8_t encodingOfTargetAddress;
+ uint32_t offsetInCFI;
+ pint_t targetAddress;
+};
+template <typename A>
+struct CFI_Atom_Info {
+ typedef typename A::pint_t pint_t;
+ pint_t address;
+ uint32_t size;
+ bool isCIE;
+ union {
+ struct {
+ CFI_Reference<A> function;
+ CFI_Reference<A> cie;
+ CFI_Reference<A> lsda;
+ uint32_t compactUnwindInfo;
+ } fdeInfo;
+ struct {
+ CFI_Reference<A> personality;
+ } cieInfo;
+ } u;
+};
+
+typedef void (*WarnFunc)(void* ref, uint64_t funcAddr, const char* msg);
+
+///
+/// DwarfInstructions maps abtract dwarf unwind instructions to a particular architecture
+///
+template <typename A, typename R>
+class DwarfInstructions
+{
+public:
+ typedef typename A::pint_t pint_t;
+ typedef typename A::sint_t sint_t;
+
+ static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn);
+
+
+ static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
+ pint_t* lsda, pint_t* personality,
+ char warningBuffer[1024]);
+
+ static int stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers);
+
+private:
+
+ enum {
+ DW_X86_64_RET_ADDR = 16
+ };
+
+ enum {
+ DW_X86_RET_ADDR = 8
+ };
+
+ static pint_t evaluateExpression(pint_t expression, A& addressSpace, const R& registers, pint_t initialStackValue);
+ static pint_t getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+ static double getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+ static v128 getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+
+ // x86 specific variants
+ static int lastRestoreReg(const Registers_x86&);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86&);
+
+ static uint32_t getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+
+ // x86_64 specific variants
+ static int lastRestoreReg(const Registers_x86_64&);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86_64&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86_64&);
+
+ static uint32_t getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86_64&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86_64&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+
+ // ppc specific variants
+ static int lastRestoreReg(const Registers_ppc&);
+ static bool isReturnAddressRegister(int regNum, const Registers_ppc&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_ppc&);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_ppc&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+};
+
+
+
+
+template <typename A, typename R>
+const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn)
+{
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ CFI_Atom_Info<A>* entry = infos;
+ CFI_Atom_Info<A>* end = &infos[infosCount];
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ pint_t currentCFI = p;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return NULL; // end marker
+ if ( entry >= end )
+ return "too little space allocated for parseCFIs";
+ pint_t nextCFI = p + cfiLength;
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // is CIE
+ const char* err = CFI_Parser<A>::parseCIE(addressSpace, currentCFI, &cieInfo);
+ if ( err != NULL )
+ return err;
+ entry->address = currentCFI;
+ entry->size = nextCFI - currentCFI;
+ entry->isCIE = true;
+ entry->u.cieInfo.personality.targetAddress = cieInfo.personality;
+ entry->u.cieInfo.personality.offsetInCFI = cieInfo.personalityOffsetInCIE;
+ entry->u.cieInfo.personality.encodingOfTargetAddress = cieInfo.personalityEncoding;
+ ++entry;
+ }
+ else {
+ // is FDE
+ entry->address = currentCFI;
+ entry->size = nextCFI - currentCFI;
+ entry->isCIE = false;
+ entry->u.fdeInfo.function.targetAddress = CFI_INVALID_ADDRESS;
+ entry->u.fdeInfo.cie.targetAddress = CFI_INVALID_ADDRESS;
+ entry->u.fdeInfo.lsda.targetAddress = CFI_INVALID_ADDRESS;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+ return "FDE points to CIE outside __eh_frame section";
+ // optimize usual case where cie is same for all FDEs
+ if ( cieStart != cieInfo.cieStart ) {
+ const char* err = CFI_Parser<A>::parseCIE(addressSpace, cieStart, &cieInfo);
+ if ( err != NULL )
+ return err;
+ }
+ entry->u.fdeInfo.cie.targetAddress = cieStart;
+ entry->u.fdeInfo.cie.offsetInCFI = p-currentCFI;
+ entry->u.fdeInfo.cie.encodingOfTargetAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+ p += 4;
+ // parse pc begin and range
+ pint_t offsetOfFunctionAddress = p-currentCFI;
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ entry->u.fdeInfo.function.targetAddress = pcStart;
+ entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
+ entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
+ // check for augmentation length
+ if ( cieInfo.fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo.lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ pint_t offsetOfLSDAAddress = p-currentCFI;
+ entry->u.fdeInfo.lsda.targetAddress = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+ entry->u.fdeInfo.lsda.offsetInCFI = offsetOfLSDAAddress;
+ entry->u.fdeInfo.lsda.encodingOfTargetAddress = cieInfo.lsdaEncoding;
+ }
+ }
+ p = endOfAug;
+ }
+ // compute compact unwind encoding
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ fdeInfo.fdeStart = currentCFI;
+ fdeInfo.fdeLength = nextCFI - currentCFI;
+ fdeInfo.fdeInstructions = p;
+ fdeInfo.pcStart = pcStart;
+ fdeInfo.pcEnd = pcStart + pcRange;
+ fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
+ typename CFI_Parser<A>::PrologInfo prolog;
+ R dummy; // for proper selection of architecture specific functions
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+ char warningBuffer[1024];
+ entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+ if ( fdeInfo.lsda != CFI_INVALID_ADDRESS )
+ entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
+ if ( warningBuffer[0] != '\0' )
+ warn(ref, fdeInfo.pcStart, warningBuffer);
+ }
+ else {
+ warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
+ entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+ }
+ ++entry;
+ }
+ p = nextCFI;
+ }
+ if ( entry != end )
+ return "wrong entry count for parseCFIs";
+ return NULL; // success
+}
+
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
+ pint_t* lsda, pint_t* personality,
+ char warningBuffer[1024])
+{
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ R dummy; // for proper selection of architecture specific functions
+ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+ *lsda = fdeInfo.lsda;
+ *personality = cieInfo.personality;
+ compact_unwind_encoding_t encoding;
+ encoding = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+ if ( fdeInfo.lsda != 0 )
+ encoding |= UNWIND_HAS_LSDA;
+ return encoding;
+ }
+ else {
+ strcpy(warningBuffer, "dwarf unwind instructions could not be parsed");
+ return encodeToUseDwarf(dummy);
+ }
+ }
+ else {
+ strcpy(warningBuffer, "dwarf FDE could not be parsed");
+ return encodeToUseDwarf(dummy);
+ }
+}
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getP(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getP(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
+
+ case CFI_Parser<A>::kRegisterInRegister:
+ return registers.getRegister(savedReg.value);
+
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for register");
+}
+
+template <typename A, typename R>
+double DwarfInstructions<A,R>::getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getDouble(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getDouble(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for float register");
+}
+
+template <typename A, typename R>
+v128 DwarfInstructions<A,R>::getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getVector(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getVector(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for vector register");
+}
+
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers)
+{
+ //fprintf(stderr, "stepWithDwarf(pc=0x%0llX, fdeStart=0x%0llX)\n", (uint64_t)pc, (uint64_t)fdeStart);
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ R newRegisters = registers;
+
+ // get pointer to cfa (architecture specific)
+ pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+ // restore registers that dwarf says were saved
+ pint_t returnAddress = 0;
+ for (int i=0; i <= lastRestoreReg(newRegisters); ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( registers.validFloatRegister(i) )
+ newRegisters.setFloatRegister(i, getSavedFloatRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else if ( registers.validVectorRegister(i) )
+ newRegisters.setVectorRegister(i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else if ( isReturnAddressRegister(i, registers) )
+ returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]);
+ else if ( registers.validRegister(i) )
+ newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else
+ return UNW_EBADREG;
+ }
+ }
+
+ // by definition the CFA is the stack pointer at the call site, so restoring SP means setting it to CFA
+ newRegisters.setSP(cfa);
+
+ // return address is address after call site instruction, so setting IP to that does a return
+ newRegisters.setIP(returnAddress);
+
+ // do the actual step by replacing the register set with the new ones
+ registers = newRegisters;
+
+ return UNW_STEP_SUCCESS;
+ }
+ }
+ return UNW_EBADFRAME;
+}
+
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::evaluateExpression(pint_t expression, A& addressSpace,
+ const R& registers, pint_t initialStackValue)
+{
+ const bool log = false;
+ pint_t p = expression;
+ pint_t expressionEnd = expression+20; // just need something until length is read
+ uint64_t length = addressSpace.getULEB128(p, expressionEnd);
+ expressionEnd = p + length;
+ if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", length);
+ pint_t stack[100];
+ pint_t* sp = stack;
+ *(++sp) = initialStackValue;
+
+ while ( p < expressionEnd ) {
+ if (log) {
+ for(pint_t* t = sp; t > stack; --t) {
+ fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t));
+ }
+ }
+ uint8_t opcode = addressSpace.get8(p++);
+ sint_t svalue;
+ pint_t value;
+ uint32_t reg;
+ switch (opcode) {
+ case DW_OP_addr:
+ // push immediate address sized value
+ value = addressSpace.getP(p);
+ p += sizeof(pint_t);
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_deref:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *(++sp) = addressSpace.getP(value);
+ if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1u:
+ // push immediate 1 byte value
+ value = addressSpace.get8(p);
+ p += 1;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1s:
+ // push immediate 1 byte signed value
+ svalue = (int8_t)addressSpace.get8(p);
+ p += 1;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const2u:
+ // push immediate 2 byte value
+ value = addressSpace.get16(p);
+ p += 2;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const2s:
+ // push immediate 2 byte signed value
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const4u:
+ // push immediate 4 byte value
+ value = addressSpace.get32(p);
+ p += 4;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const4s:
+ // push immediate 4 byte signed value
+ svalue = (int32_t)addressSpace.get32(p);
+ p += 4;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const8u:
+ // push immediate 8 byte value
+ value = addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const8s:
+ // push immediate 8 byte signed value
+ value = (int32_t)addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_constu:
+ // push immediate ULEB128 value
+ value = addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_consts:
+ // push immediate SLEB128 value
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_dup:
+ // push top of stack
+ value = *sp;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate top of stack\n");
+ break;
+
+ case DW_OP_drop:
+ // pop
+ --sp;
+ if (log) fprintf(stderr, "pop top of stack\n");
+ break;
+
+ case DW_OP_over:
+ // dup second
+ value = sp[-1];
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate second in stack\n");
+ break;
+
+ case DW_OP_pick:
+ // pick from
+ reg = addressSpace.get8(p);
+ p += 1;
+ value = sp[-reg];
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate %d in stack\n", reg);
+ break;
+
+ case DW_OP_swap:
+ // swap top two
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = value;
+ if (log) fprintf(stderr, "swap top of stack\n");
+ break;
+
+ case DW_OP_rot:
+ // rotate top three
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = value;
+ if (log) fprintf(stderr, "rotate top three of stack\n");
+ break;
+
+ case DW_OP_xderef:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *sp = *((uint64_t*)value);
+ if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_abs:
+ svalue = *sp;
+ if ( svalue < 0 )
+ *sp = -svalue;
+ if (log) fprintf(stderr, "abs\n");
+ break;
+
+ case DW_OP_and:
+ value = *sp--;
+ *sp &= value;
+ if (log) fprintf(stderr, "and\n");
+ break;
+
+ case DW_OP_div:
+ svalue = *sp--;
+ *sp = *sp / svalue;
+ if (log) fprintf(stderr, "div\n");
+ break;
+
+ case DW_OP_minus:
+ svalue = *sp--;
+ *sp = *sp - svalue;
+ if (log) fprintf(stderr, "minus\n");
+ break;
+
+ case DW_OP_mod:
+ svalue = *sp--;
+ *sp = *sp % svalue;
+ if (log) fprintf(stderr, "module\n");
+ break;
+
+ case DW_OP_mul:
+ svalue = *sp--;
+ *sp = *sp * svalue;
+ if (log) fprintf(stderr, "mul\n");
+ break;
+
+ case DW_OP_neg:
+ *sp = 0 - *sp;
+ if (log) fprintf(stderr, "neg\n");
+ break;
+
+ case DW_OP_not:
+ svalue = *sp;
+ *sp = ~svalue;
+ if (log) fprintf(stderr, "not\n");
+ break;
+
+ case DW_OP_or:
+ value = *sp--;
+ *sp |= value;
+ if (log) fprintf(stderr, "or\n");
+ break;
+
+ case DW_OP_plus:
+ value = *sp--;
+ *sp += value;
+ if (log) fprintf(stderr, "plus\n");
+ break;
+
+ case DW_OP_plus_uconst:
+ // pop stack, add uelb128 constant, push result
+ *sp += addressSpace.getULEB128(p, expressionEnd);
+ if (log) fprintf(stderr, "add constant\n");
+ break;
+
+ case DW_OP_shl:
+ value = *sp--;
+ *sp = *sp << value;
+ if (log) fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shr:
+ value = *sp--;
+ *sp = *sp >> value;
+ if (log) fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shra:
+ value = *sp--;
+ svalue = *sp;
+ *sp = svalue >> value;
+ if (log) fprintf(stderr, "shift left arithmetric\n");
+ break;
+
+ case DW_OP_xor:
+ value = *sp--;
+ *sp ^= value;
+ if (log) fprintf(stderr, "xor\n");
+ break;
+
+ case DW_OP_skip:
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ p += svalue;
+ if (log) fprintf(stderr, "skip %lld\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_bra:
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ if ( *sp-- )
+ p += svalue;
+ if (log) fprintf(stderr, "bra %lld\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_eq:
+ value = *sp--;
+ *sp = (*sp == value);
+ if (log) fprintf(stderr, "eq\n");
+ break;
+
+ case DW_OP_ge:
+ value = *sp--;
+ *sp = (*sp >= value);
+ if (log) fprintf(stderr, "ge\n");
+ break;
+
+ case DW_OP_gt:
+ value = *sp--;
+ *sp = (*sp > value);
+ if (log) fprintf(stderr, "gt\n");
+ break;
+
+ case DW_OP_le:
+ value = *sp--;
+ *sp = (*sp <= value);
+ if (log) fprintf(stderr, "le\n");
+ break;
+
+ case DW_OP_lt:
+ value = *sp--;
+ *sp = (*sp < value);
+ if (log) fprintf(stderr, "lt\n");
+ break;
+
+ case DW_OP_ne:
+ value = *sp--;
+ *sp = (*sp != value);
+ if (log) fprintf(stderr, "ne\n");
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ value = opcode - DW_OP_lit0;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ reg = opcode - DW_OP_reg0;
+ *(++sp) = registers.getRegister(reg);
+ if (log) fprintf(stderr, "push reg %d\n", reg);
+ break;
+
+ case DW_OP_regx:
+ reg = addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg);
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ reg = opcode - DW_OP_breg0;
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg) + svalue;
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_bregx:
+ reg = addressSpace.getULEB128(p, expressionEnd);
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg) + svalue;
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_fbreg:
+ ABORT("DW_OP_fbreg not implemented");
+ break;
+
+ case DW_OP_piece:
+ ABORT("DW_OP_piece not implemented");
+ break;
+
+ case DW_OP_deref_size:
+ // pop stack, dereference, push result
+ value = *sp--;
+ switch ( addressSpace.get8(p++) ) {
+ case 1:
+ value = addressSpace.get8(value);
+ break;
+ case 2:
+ value = addressSpace.get16(value);
+ break;
+ case 4:
+ value = addressSpace.get32(value);
+ break;
+ case 8:
+ value = addressSpace.get64(value);
+ break;
+ default:
+ ABORT("DW_OP_deref_size with bad size");
+ }
+ *(++sp) = value;
+ if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_xderef_size:
+ case DW_OP_nop:
+ case DW_OP_push_object_addres:
+ case DW_OP_call2:
+ case DW_OP_call4:
+ case DW_OP_call_ref:
+ default:
+ ABORT("dwarf opcode not implemented");
+ }
+
+ }
+ if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t)*sp);
+ return *sp;
+}
+
+
+
+//
+// x86_64 specific functions
+//
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86_64&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_64_RET_ADDR );
+ return DW_X86_64_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86_64&)
+{
+ return (regNum == DW_X86_64_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_x86_64& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for x86_64 cfa");
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86_64&)
+{
+ return UNWIND_X86_64_MODE_DWARF;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86&)
+{
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 32) ) {
+ failure = true;
+ return 0;
+ }
+ unsigned int slotIndex = regOffsetFromBaseOffset/8;
+
+ switch ( reg ) {
+ case UNW_X86_64_RBX:
+ return UNWIND_X86_64_REG_RBX << (slotIndex*3);
+ case UNW_X86_64_R12:
+ return UNWIND_X86_64_REG_R12 << (slotIndex*3);
+ case UNW_X86_64_R13:
+ return UNWIND_X86_64_REG_R13 << (slotIndex*3);
+ case UNW_X86_64_R14:
+ return UNWIND_X86_64_REG_R14 << (slotIndex*3);
+ case UNW_X86_64_R15:
+ return UNWIND_X86_64_REG_R15 << (slotIndex*3);
+ }
+
+ // invalid register
+ failure = true;
+ return 0;
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86_64& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+
+ // don't create compact unwind info for unsupported dwarf kinds
+ if ( prolog.registerSavedMoreThanOnce ) {
+ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ if ( prolog.cfaOffsetWasNegative ) {
+ strcpy(warningBuffer, "cfa had negative offset (dwarf might contain epilog)");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ if ( prolog.spExtraArgSize != 0 ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ // figure out which kind of frame this function uses
+ bool standardRBPframe = (
+ (prolog.cfaRegister == UNW_X86_64_RBP)
+ && (prolog.cfaRegisterOffset == 16)
+ && (prolog.savedRegisters[UNW_X86_64_RBP].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_X86_64_RBP].value == -16) );
+ bool standardRSPframe = (prolog.cfaRegister == UNW_X86_64_RSP);
+ if ( !standardRBPframe && !standardRSPframe ) {
+ // no compact encoding for this
+ strcpy(warningBuffer, "does not use RBP or RSP based frame");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ // scan which registers are saved
+ int saveRegisterCount = 0;
+ bool rbxSaved = false;
+ bool r12Saved = false;
+ bool r13Saved = false;
+ bool r14Saved = false;
+ bool r15Saved = false;
+ bool rbpSaved = false;
+ for (int i=0; i < 64; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ switch (i) {
+ case UNW_X86_64_RBX:
+ rbxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R12:
+ r12Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R13:
+ r13Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R14:
+ r14Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R15:
+ r15Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_RBP:
+ rbpSaved = true;
+ ++saveRegisterCount;
+ break;
+ case DW_X86_64_RET_ADDR:
+ break;
+ default:
+ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ }
+ }
+ const int64_t cfaOffsetRBX = prolog.savedRegisters[UNW_X86_64_RBX].value;
+ const int64_t cfaOffsetR12 = prolog.savedRegisters[UNW_X86_64_R12].value;
+ const int64_t cfaOffsetR13 = prolog.savedRegisters[UNW_X86_64_R13].value;
+ const int64_t cfaOffsetR14 = prolog.savedRegisters[UNW_X86_64_R14].value;
+ const int64_t cfaOffsetR15 = prolog.savedRegisters[UNW_X86_64_R15].value;
+ const int64_t cfaOffsetRBP = prolog.savedRegisters[UNW_X86_64_RBP].value;
+
+ // encode standard RBP frames
+ compact_unwind_encoding_t encoding = 0;
+ if ( standardRBPframe ) {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | rbp |
+ // +--------------+ <- rbp
+ // ~ ~
+ // +--------------+
+ // | saved reg3 |
+ // +--------------+ <- CFA - offset+16
+ // | saved reg2 |
+ // +--------------+ <- CFA - offset+8
+ // | saved reg1 |
+ // +--------------+ <- CFA - offset
+ // | |
+ // +--------------+
+ // | |
+ // <- rsp
+ //
+ encoding = UNWIND_X86_64_MODE_RBP_FRAME;
+
+ // find save location of farthest register from rbp
+ int furthestCfaOffset = 0;
+ if ( rbxSaved & (cfaOffsetRBX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetRBX;
+ if ( r12Saved & (cfaOffsetR12 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR12;
+ if ( r13Saved & (cfaOffsetR13 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR13;
+ if ( r14Saved & (cfaOffsetR14 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR14;
+ if ( r15Saved & (cfaOffsetR15 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR15;
+
+ if ( furthestCfaOffset == 0 ) {
+ // no registers saved, nothing more to encode
+ return encoding;
+ }
+
+ // add stack offset to encoding
+ int rbpOffset = furthestCfaOffset + 16;
+ int encodedOffset = rbpOffset/(-8);
+ if ( encodedOffset > 255 ) {
+ strcpy(warningBuffer, "offset of saved registers too far to encode");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET));
+
+ // add register saved from each stack location
+ bool encodingFailure = false;
+ if ( rbxSaved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_RBX, cfaOffsetRBX - furthestCfaOffset, encodingFailure);
+ if ( r12Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R12, cfaOffsetR12 - furthestCfaOffset, encodingFailure);
+ if ( r13Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R13, cfaOffsetR13 - furthestCfaOffset, encodingFailure);
+ if ( r14Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R14, cfaOffsetR14 - furthestCfaOffset, encodingFailure);
+ if ( r15Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R15, cfaOffsetR15 - furthestCfaOffset, encodingFailure);
+
+ if ( encodingFailure ){
+ strcpy(warningBuffer, "saved registers not contiguous");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ return encoding;
+ }
+ else {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | saved reg1 |
+ // +--------------+ <- CFA - 16
+ // | saved reg2 |
+ // +--------------+ <- CFA - 24
+ // | saved reg3 |
+ // +--------------+ <- CFA - 32
+ // | saved reg4 |
+ // +--------------+ <- CFA - 40
+ // | saved reg5 |
+ // +--------------+ <- CFA - 48
+ // | saved reg6 |
+ // +--------------+ <- CFA - 56
+ // | |
+ // <- esp
+ //
+
+ // for RSP based frames we need to encode stack size in unwind info
+ encoding = UNWIND_X86_64_MODE_STACK_IMMD;
+ uint64_t stackValue = prolog.cfaRegisterOffset / 8;
+ uint32_t stackAdjust = 0;
+ bool immedStackSize = true;
+ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ if ( stackValue > stackMaxImmedValue ) {
+ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
+ stackValue = functionContentAdjustStackIns - funcAddr;
+ immedStackSize = false;
+ if ( stackAdjust > 7 ) {
+ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ encoding = UNWIND_X86_64_MODE_STACK_IND;
+ }
+
+
+ // validate that saved registers are all within 6 slots abutting return address
+ int registers[6];
+ for (int i=0; i < 6;++i)
+ registers[i] = 0;
+ if ( r15Saved ) {
+ if ( cfaOffsetR15 < -56 ) {
+ strcpy(warningBuffer, "r15 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR15+56)/8] = UNWIND_X86_64_REG_R15;
+ }
+ if ( r14Saved ) {
+ if ( cfaOffsetR14 < -56 ) {
+ strcpy(warningBuffer, "r14 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR14+56)/8] = UNWIND_X86_64_REG_R14;
+ }
+ if ( r13Saved ) {
+ if ( cfaOffsetR13 < -56 ) {
+ strcpy(warningBuffer, "r13 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR13+56)/8] = UNWIND_X86_64_REG_R13;
+ }
+ if ( r12Saved ) {
+ if ( cfaOffsetR12 < -56 ) {
+ strcpy(warningBuffer, "r12 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR12+56)/8] = UNWIND_X86_64_REG_R12;
+ }
+ if ( rbxSaved ) {
+ if ( cfaOffsetRBX < -56 ) {
+ strcpy(warningBuffer, "rbx is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetRBX+56)/8] = UNWIND_X86_64_REG_RBX;
+ }
+ if ( rbpSaved ) {
+ if ( cfaOffsetRBP < -56 ) {
+ strcpy(warningBuffer, "rbp is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetRBP+56)/8] = UNWIND_X86_64_REG_RBP;
+ }
+
+ // validate that saved registers are contiguous and abut return address on stack
+ for (int i=0; i < saveRegisterCount; ++i) {
+ if ( registers[5-i] == 0 ) {
+ strcpy(warningBuffer, "registers not save contiguously in stack");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ }
+
+ // encode register permutation
+ // the 10-bits are encoded differently depending on the number of registers saved
+ int renumregs[6];
+ for (int i=6-saveRegisterCount; i < 6; ++i) {
+ int countless = 0;
+ for (int j=6-saveRegisterCount; j < i; ++j) {
+ if ( registers[j] < registers[i] )
+ ++countless;
+ }
+ renumregs[i] = registers[i] - countless -1;
+ }
+ uint32_t permutationEncoding = 0;
+ switch ( saveRegisterCount ) {
+ case 6:
+ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+ break;
+ case 5:
+ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+ break;
+ case 4:
+ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+ break;
+ case 3:
+ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+ break;
+ case 2:
+ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+ break;
+ case 1:
+ permutationEncoding |= (renumregs[5]);
+ break;
+ }
+
+ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_SIZE));
+ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_ADJUST));
+ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT));
+ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION));
+ return encoding;
+ }
+}
+
+
+
+
+//
+// x86 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_RET_ADDR );
+ return DW_X86_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86&)
+{
+ return (regNum == DW_X86_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_x86& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for x86 cfa");
+}
+
+
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 16) ) {
+ failure = true;
+ return 0;
+ }
+ unsigned int slotIndex = regOffsetFromBaseOffset/4;
+
+ switch ( reg ) {
+ case UNW_X86_EBX:
+ return UNWIND_X86_REG_EBX << (slotIndex*3);
+ case UNW_X86_ECX:
+ return UNWIND_X86_REG_ECX << (slotIndex*3);
+ case UNW_X86_EDX:
+ return UNWIND_X86_REG_EDX << (slotIndex*3);
+ case UNW_X86_EDI:
+ return UNWIND_X86_REG_EDI << (slotIndex*3);
+ case UNW_X86_ESI:
+ return UNWIND_X86_REG_ESI << (slotIndex*3);
+ }
+
+ // invalid register
+ failure = true;
+ return 0;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+
+ // don't create compact unwind info for unsupported dwarf kinds
+ if ( prolog.registerSavedMoreThanOnce ) {
+ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ if ( prolog.spExtraArgSize != 0 ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ // figure out which kind of frame this function uses
+ bool standardEBPframe = (
+ (prolog.cfaRegister == UNW_X86_EBP)
+ && (prolog.cfaRegisterOffset == 8)
+ && (prolog.savedRegisters[UNW_X86_EBP].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_X86_EBP].value == -8) );
+ bool standardESPframe = (prolog.cfaRegister == UNW_X86_ESP);
+ if ( !standardEBPframe && !standardESPframe ) {
+ // no compact encoding for this
+ strcpy(warningBuffer, "does not use EBP or ESP based frame");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ // scan which registers are saved
+ int saveRegisterCount = 0;
+ bool ebxSaved = false;
+ bool ecxSaved = false;
+ bool edxSaved = false;
+ bool esiSaved = false;
+ bool ediSaved = false;
+ bool ebpSaved = false;
+ for (int i=0; i < 64; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ return UNWIND_X86_MODE_DWARF;
+ }
+ switch (i) {
+ case UNW_X86_EBX:
+ ebxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_ECX:
+ ecxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EDX:
+ edxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_ESI:
+ esiSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EDI:
+ ediSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EBP:
+ ebpSaved = true;
+ ++saveRegisterCount;
+ break;
+ case DW_X86_RET_ADDR:
+ break;
+ default:
+ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+ return UNWIND_X86_MODE_DWARF;
+ }
+ }
+ }
+ const int32_t cfaOffsetEBX = prolog.savedRegisters[UNW_X86_EBX].value;
+ const int32_t cfaOffsetECX = prolog.savedRegisters[UNW_X86_ECX].value;
+ const int32_t cfaOffsetEDX = prolog.savedRegisters[UNW_X86_EDX].value;
+ const int32_t cfaOffsetEDI = prolog.savedRegisters[UNW_X86_EDI].value;
+ const int32_t cfaOffsetESI = prolog.savedRegisters[UNW_X86_ESI].value;
+ const int32_t cfaOffsetEBP = prolog.savedRegisters[UNW_X86_EBP].value;
+
+ // encode standard RBP frames
+ compact_unwind_encoding_t encoding = 0;
+ if ( standardEBPframe ) {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | ebp |
+ // +--------------+ <- ebp
+ // ~ ~
+ // +--------------+
+ // | saved reg3 |
+ // +--------------+ <- CFA - offset+8
+ // | saved reg2 |
+ // +--------------+ <- CFA - offset+e
+ // | saved reg1 |
+ // +--------------+ <- CFA - offset
+ // | |
+ // +--------------+
+ // | |
+ // <- esp
+ //
+ encoding = UNWIND_X86_MODE_EBP_FRAME;
+
+ // find save location of farthest register from ebp
+ int furthestCfaOffset = 0;
+ if ( ebxSaved & (cfaOffsetEBX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEBX;
+ if ( ecxSaved & (cfaOffsetECX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetECX;
+ if ( edxSaved & (cfaOffsetEDX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEDX;
+ if ( ediSaved & (cfaOffsetEDI < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEDI;
+ if ( esiSaved & (cfaOffsetESI < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetESI;
+
+ if ( furthestCfaOffset == 0 ) {
+ // no registers saved, nothing more to encode
+ return encoding;
+ }
+
+ // add stack offset to encoding
+ int ebpOffset = furthestCfaOffset + 8;
+ int encodedOffset = ebpOffset/(-4);
+ if ( encodedOffset > 255 ) {
+ strcpy(warningBuffer, "offset of saved registers too far to encode");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_EBP_FRAME_OFFSET));
+
+ // add register saved from each stack location
+ bool encodingFailure = false;
+ if ( ebxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EBX, cfaOffsetEBX - furthestCfaOffset, encodingFailure);
+ if ( ecxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_ECX, cfaOffsetECX - furthestCfaOffset, encodingFailure);
+ if ( edxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EDX, cfaOffsetEDX - furthestCfaOffset, encodingFailure);
+ if ( ediSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EDI, cfaOffsetEDI - furthestCfaOffset, encodingFailure);
+ if ( esiSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_ESI, cfaOffsetESI - furthestCfaOffset, encodingFailure);
+
+ if ( encodingFailure ){
+ strcpy(warningBuffer, "saved registers not contiguous");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ return encoding;
+ }
+ else {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | saved reg1 |
+ // +--------------+ <- CFA - 8
+ // | saved reg2 |
+ // +--------------+ <- CFA - 12
+ // | saved reg3 |
+ // +--------------+ <- CFA - 16
+ // | saved reg4 |
+ // +--------------+ <- CFA - 20
+ // | saved reg5 |
+ // +--------------+ <- CFA - 24
+ // | saved reg6 |
+ // +--------------+ <- CFA - 28
+ // | |
+ // <- esp
+ //
+
+ // for ESP based frames we need to encode stack size in unwind info
+ encoding = UNWIND_X86_MODE_STACK_IMMD;
+ uint64_t stackValue = prolog.cfaRegisterOffset / 4;
+ uint32_t stackAdjust = 0;
+ bool immedStackSize = true;
+ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_FRAMELESS_STACK_SIZE);
+ if ( stackValue > stackMaxImmedValue ) {
+ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+ stackValue = functionContentAdjustStackIns - funcAddr;
+ immedStackSize = false;
+ if ( stackAdjust > 7 ) {
+ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ encoding = UNWIND_X86_MODE_STACK_IND;
+ }
+
+
+ // validate that saved registers are all within 6 slots abutting return address
+ int registers[6];
+ for (int i=0; i < 6;++i)
+ registers[i] = 0;
+ if ( ebxSaved ) {
+ if ( cfaOffsetEBX < -28 ) {
+ strcpy(warningBuffer, "ebx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEBX+28)/4] = UNWIND_X86_REG_EBX;
+ }
+ if ( ecxSaved ) {
+ if ( cfaOffsetECX < -28 ) {
+ strcpy(warningBuffer, "ecx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetECX+28)/4] = UNWIND_X86_REG_ECX;
+ }
+ if ( edxSaved ) {
+ if ( cfaOffsetEDX < -28 ) {
+ strcpy(warningBuffer, "edx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEDX+28)/4] = UNWIND_X86_REG_EDX;
+ }
+ if ( ediSaved ) {
+ if ( cfaOffsetEDI < -28 ) {
+ strcpy(warningBuffer, "edi is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEDI+28)/4] = UNWIND_X86_REG_EDI;
+ }
+ if ( esiSaved ) {
+ if ( cfaOffsetESI < -28 ) {
+ strcpy(warningBuffer, "esi is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetESI+28)/4] = UNWIND_X86_REG_ESI;
+ }
+ if ( ebpSaved ) {
+ if ( cfaOffsetEBP < -28 ) {
+ strcpy(warningBuffer, "ebp is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEBP+28)/4] = UNWIND_X86_REG_EBP;
+ }
+
+ // validate that saved registers are contiguous and abut return address on stack
+ for (int i=0; i < saveRegisterCount; ++i) {
+ if ( registers[5-i] == 0 ) {
+ strcpy(warningBuffer, "registers not save contiguously in stack");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ }
+
+ // encode register permutation
+ // the 10-bits are encoded differently depending on the number of registers saved
+ int renumregs[6];
+ for (int i=6-saveRegisterCount; i < 6; ++i) {
+ int countless = 0;
+ for (int j=6-saveRegisterCount; j < i; ++j) {
+ if ( registers[j] < registers[i] )
+ ++countless;
+ }
+ renumregs[i] = registers[i] - countless -1;
+ }
+ uint32_t permutationEncoding = 0;
+ switch ( saveRegisterCount ) {
+ case 6:
+ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+ break;
+ case 5:
+ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+ break;
+ case 4:
+ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+ break;
+ case 3:
+ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+ break;
+ case 2:
+ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+ break;
+ case 1:
+ permutationEncoding |= (renumregs[5]);
+ break;
+ }
+
+ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_SIZE));
+ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_ADJUST));
+ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_COUNT));
+ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION));
+ return encoding;
+ }
+}
+
+
+
+
+
+
+
+//
+// ppc specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_ppc&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_PPC_SPEFSCR );
+ return UNW_PPC_SPEFSCR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_ppc&)
+{
+ return (regNum == UNW_PPC_LR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_ppc& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for ppc cfa");
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_ppc&)
+{
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_ppc& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+
+} // namespace lldb_private
+
+
+#endif // __DWARF_INSTRUCTIONS_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp
new file mode 100644
index 00000000000..b11cb8ce441
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp
@@ -0,0 +1,869 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- DwarfParser.hpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_PARSER_HPP__
+#define __DWARF_PARSER_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vector>
+
+#include "libunwind.h"
+#include "dwarf2.h"
+
+#include "AddressSpace.hpp"
+#include "RemoteUnwindProfile.h"
+
+namespace lldb_private {
+
+
+///
+/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
+/// See Dwarf Spec for details:
+/// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A>
+class CFI_Parser
+{
+public:
+ typedef typename A::pint_t pint_t;
+
+ ///
+ /// Information encoded in a CIE (Common Information Entry)
+ ///
+ struct CIE_Info {
+ pint_t cieStart;
+ pint_t cieLength;
+ pint_t cieInstructions;
+ uint8_t pointerEncoding;
+ uint8_t lsdaEncoding;
+ uint8_t personalityEncoding;
+ uint8_t personalityOffsetInCIE;
+ pint_t personality;
+ int codeAlignFactor;
+ int dataAlignFactor;
+ bool isSignalFrame;
+ bool fdesHaveAugmentationData;
+ };
+
+ ///
+ /// Information about an FDE (Frame Description Entry)
+ ///
+ struct FDE_Info {
+ pint_t fdeStart;
+ pint_t fdeLength;
+ pint_t fdeInstructions;
+ pint_t pcStart;
+ pint_t pcEnd;
+ pint_t lsda;
+ };
+
+ ///
+ /// Used by linker when parsing __eh_frame section
+ ///
+ struct FDE_Reference {
+ pint_t address;
+ uint32_t offsetInFDE;
+ uint8_t encodingOfAddress;
+ };
+ struct FDE_Atom_Info {
+ pint_t fdeAddress;
+ FDE_Reference function;
+ FDE_Reference cie;
+ FDE_Reference lsda;
+ };
+ struct CIE_Atom_Info {
+ pint_t cieAddress;
+ FDE_Reference personality;
+ };
+
+
+ ///
+ /// Information about a frame layout and registers saved determined
+ /// by "running" the dwarf FDE "instructions"
+ ///
+ enum { kMaxRegisterNumber = 120 };
+ enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
+ kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
+ struct RegisterLocation {
+ RegisterSavedWhere location;
+ int64_t value;
+ };
+ struct PrologInfo {
+ uint32_t cfaRegister;
+ int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
+ int64_t cfaExpression; // CFA = expression
+ bool registersInOtherRegisters;
+ bool registerSavedMoreThanOnce;
+ bool cfaOffsetWasNegative;
+ uint32_t spExtraArgSize;
+ uint32_t codeOffsetAtStackDecrement;
+
+ RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers
+ };
+
+ struct PrologInfoStackEntry {
+ PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
+ : next(n), info(i) {}
+ PrologInfoStackEntry* next;
+ PrologInfo info;
+ };
+
+ static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+ static bool functionFuncBoundsViaFDE(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, std::vector<FuncBounds> &funcbounds);
+#endif
+
+ static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+ static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
+ static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
+ static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
+
+ static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
+
+private:
+ static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
+ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
+
+};
+
+
+///
+/// Parse a FDE into a CIE_Info and an FDE_Info
+///
+template <typename A>
+const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+ pint_t p = fdeStart;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return "FDE has zero length"; // end marker
+ uint32_t ciePointer = addressSpace.get32(p);
+ if ( ciePointer == 0 )
+ return "FDE is really a CIE"; // this is a CIE not an FDE
+ pint_t nextCFI = p + cfiLength;
+ pint_t cieStart = p-ciePointer;
+ const char* err = parseCIE(addressSpace, cieStart, cieInfo);
+ if (err != NULL)
+ return err;
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if ( cieInfo->fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo->lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = fdeStart;
+ fdeInfo->fdeLength = nextCFI - fdeStart;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart+pcRange;
+ return NULL; // success
+}
+
+
+///
+/// Scan an eh_frame section to find an FDE for a pc
+///
+template <typename A>
+bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+ //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
+ pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
+ const pint_t ehSectionEnd = p + sectionLength;
+ while ( p < ehSectionEnd ) {
+ pint_t currentCFI = p;
+ //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return false; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // skip over CIEs
+ p += cfiLength;
+ }
+ else {
+ // process FDE to see if it covers pc
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
+ if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if ( cieInfo->fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo->lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = currentCFI;
+ fdeInfo->fdeLength = nextCFI - currentCFI;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart+pcRange;
+ //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ return true;
+ }
+ else {
+ //fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // pc is not in begin/range, skip this FDE
+ }
+ }
+ else {
+ // malformed CIE, now augmentation describing pc range encoding
+ //fprintf(stderr, "malformed CIE\n");
+ }
+ }
+ else {
+ // malformed FDE. CIE is bad
+ //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
+ // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
+ }
+ p = nextCFI;
+ }
+ }
+ //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
+ return false;
+}
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+/// Scan an eh_frame section to find all the function start addresses
+/// This is only made for working with libunwind-remote. It copies
+/// the eh_frame section into local memory and steps through it quickly
+/// to find the start addresses of the CFIs.
+///
+template <typename A>
+bool CFI_Parser<A>::functionFuncBoundsViaFDE(A& addressSpace, pint_t ehSectionStart,
+ uint32_t sectionLength, std::vector<FuncBounds> &funcbounds)
+{
+ //fprintf(stderr, "functionFuncBoundsViaFDE(0x%llX)\n", (long long)pc);
+ pint_t p = ehSectionStart;
+ const pint_t ehSectionEnd = p + sectionLength;
+ pint_t lastCieSeen = (pint_t) -1;
+ CIE_Info cieInfo;
+ while ( p < ehSectionEnd ) {
+ //fprintf(stderr, "functionFuncBoundsViaFDE() CFI at 0x%llX\n", (long long)p);
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return false; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // skip over CIEs
+ p += cfiLength;
+ }
+ else {
+ // process FDE to see if it covers pc
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
+ const char *errmsg;
+ // don't re-parse the cie if this fde is pointing to one we already parsed
+ if (cieStart == lastCieSeen) {
+ errmsg = NULL;
+ }
+ else {
+ errmsg = parseCIE(addressSpace, cieStart, &cieInfo);
+ if (errmsg == NULL)
+ lastCieSeen = cieStart;
+ }
+ if ( errmsg == NULL ) {
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ funcbounds.push_back(FuncBounds(pcStart, pcStart + pcRange));
+ }
+ else {
+ // malformed CIE, now augmentation describing pc range encoding
+ //fprintf(stderr, "malformed CIE\n");
+ return false;
+ }
+ }
+ else {
+ // malformed FDE. CIE is bad
+ //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
+ // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
+ return false;
+ }
+ p = nextCFI;
+ }
+ }
+ return true;
+}
+#endif // SUPPORT_REMOTE_UNWINDING
+
+
+
+///
+/// Extract info from a CIE
+///
+template <typename A>
+const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
+{
+ //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
+ cieInfo->pointerEncoding = 0;
+ cieInfo->lsdaEncoding = 0;
+ cieInfo->personalityEncoding = 0;
+ cieInfo->personalityOffsetInCIE = 0;
+ cieInfo->personality = 0;
+ cieInfo->codeAlignFactor = 0;
+ cieInfo->dataAlignFactor = 0;
+ cieInfo->isSignalFrame = false;
+ cieInfo->fdesHaveAugmentationData = false;
+ cieInfo->cieStart = cie;
+ pint_t p = cie;
+ uint64_t cieLength = addressSpace.get32(p);
+ p += 4;
+ pint_t cieContentEnd = p + cieLength;
+ if ( cieLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cieLength = addressSpace.get64(p);
+ p += 8;
+ cieContentEnd = p + cieLength;
+ }
+ if ( cieLength == 0 )
+ return false;
+ // CIE ID is always 0
+ if ( addressSpace.get32(p) != 0 )
+ return "CIE ID is not zero";
+ p += 4;
+ // Version is always 1 or 3
+ uint8_t version = addressSpace.get8(p);
+ if ( (version != 1) && (version != 3) )
+ return "CIE version is not 1 or 3";
+ ++p;
+ // save start of augmentation string and find end
+ pint_t strStart = p;
+ while ( addressSpace.get8(p) != 0 )
+ ++p;
+ ++p;
+ // parse code aligment factor
+ cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
+ // parse data alignment factor
+ cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
+ // parse return address register
+ addressSpace.getULEB128(p, cieContentEnd);
+ // parse augmentation data based on augmentation string
+ const char* result = NULL;
+ if ( addressSpace.get8(strStart) == 'z' ) {
+ // parse augmentation data length
+ addressSpace.getULEB128(p, cieContentEnd);
+ for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
+ switch ( addressSpace.get8(s) ) {
+ case 'z':
+ cieInfo->fdesHaveAugmentationData = true;
+ break;
+ case 'P':
+ cieInfo->personalityEncoding = addressSpace.get8(p);
+ ++p;
+ cieInfo->personalityOffsetInCIE = p-cie;
+ cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+ break;
+ case 'L':
+ cieInfo->lsdaEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'R':
+ cieInfo->pointerEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'S':
+ cieInfo->isSignalFrame = true;
+ break;
+ default:
+ // ignore unknown letters
+ break;
+ }
+ }
+ }
+ cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+ cieInfo->cieInstructions = p;
+ return result;
+}
+
+
+template <typename A>
+uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
+{
+ uint32_t count = 0;
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return count; // end marker
+ ++count;
+ p += cfiLength;
+ }
+ return count;
+}
+
+
+
+template <typename A>
+const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
+{
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ pint_t currentCFI = p;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return NULL; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // is CIE
+ CIE_Info cieInfo;
+ const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
+ if ( err != NULL )
+ return err;
+ CIE_Atom_Info entry;
+ entry.cieAddress = currentCFI;
+ entry.personality.address = cieInfo.personality;
+ entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
+ entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
+ cies.push_back(entry);
+ p += cfiLength;
+ }
+ else {
+ // is FDE
+ FDE_Atom_Info entry;
+ entry.fdeAddress = currentCFI;
+ entry.function.address = 0;
+ entry.cie.address = 0;
+ entry.lsda.address = 0;
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+ return "FDE points to CIE outside __eh_frame section";
+ CIE_Info cieInfo;
+ const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
+ if ( err != NULL )
+ return err;
+ entry.cie.address = cieStart;
+ entry.cie.offsetInFDE = p-currentCFI;
+ entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+ p += 4;
+ // parse pc begin and range
+ pint_t offsetOfFunctionAddress = p-currentCFI;
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ entry.function.address = pcStart;
+ entry.function.offsetInFDE = offsetOfFunctionAddress;
+ entry.function.encodingOfAddress = cieInfo.pointerEncoding;
+ // skip over augmentation length
+ if ( cieInfo.fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
+ pint_t offsetOfLSDAAddress = p-currentCFI;
+ entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+ entry.lsda.offsetInFDE = offsetOfLSDAAddress;
+ entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
+ }
+ p = endOfAug;
+ }
+ fdes.push_back(entry);
+ p = nextCFI;
+ }
+ }
+ return NULL; // success
+}
+
+
+
+///
+/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
+///
+template <typename A>
+bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
+{
+ // clear results
+ bzero(results, sizeof(PrologInfo));
+ PrologInfoStackEntry* rememberStack = NULL;
+
+ // parse CIE then FDE instructions
+ return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength,
+ cieInfo, (pint_t)(-1), rememberStack, results)
+ && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength,
+ cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
+}
+
+
+///
+/// "run" the dwarf instructions
+///
+template <typename A>
+bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
+ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
+{
+ const bool logDwarf = false;
+ pint_t p = instructions;
+ uint32_t codeOffset = 0;
+ PrologInfo initialState = *results;
+
+ // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
+ while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
+ uint64_t reg;
+ uint64_t reg2;
+ int64_t offset;
+ uint64_t length;
+ uint8_t opcode = addressSpace.get8(p);
+ uint8_t operand;
+ PrologInfoStackEntry* entry;
+ ++p;
+ switch (opcode) {
+ case DW_CFA_nop:
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
+ break;
+ case DW_CFA_set_loc:
+ codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
+ break;
+ case DW_CFA_advance_loc1:
+ codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+ p += 1;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_advance_loc2:
+ codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+ p += 2;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_advance_loc4:
+ codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+ p += 4;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_restore_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_undefined:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterUnused;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_same_value:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ reg2 = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( reg2 > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterInRegister;
+ results->savedRegisters[reg].value = reg2;
+ results->registersInOtherRegisters = true;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
+ break;
+ case DW_CFA_remember_state:
+ // avoid operator new, because that would be an upward dependency
+ entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
+ if ( entry != NULL ) {
+ entry->next = rememberStack;
+ entry->info = *results;
+ rememberStack = entry;
+ }
+ else {
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
+ break;
+ case DW_CFA_restore_state:
+ if ( rememberStack != NULL ) {
+ PrologInfoStackEntry* top = rememberStack;
+ *results = top->info;
+ rememberStack = top->next;
+ free((char*)top);
+ }
+ else {
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
+ break;
+ case DW_CFA_def_cfa:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ results->cfaRegisterOffset = offset;
+ if ( offset > 0x80000000 )
+ results->cfaOffsetWasNegative = true;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
+ break;
+ case DW_CFA_def_cfa_offset:
+ results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
+ results->codeOffsetAtStackDecrement = codeOffset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
+ break;
+ case DW_CFA_def_cfa_expression:
+ results->cfaRegister = 0;
+ results->cfaExpression = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
+ results->cfaExpression, length);
+ break;
+ case DW_CFA_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterAtExpression;
+ results->savedRegisters[reg].value = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_offset_extended_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ results->cfaRegisterOffset = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->codeOffsetAtStackDecrement = codeOffset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
+ break;
+ case DW_CFA_val_offset:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
+ break;
+ case DW_CFA_val_offset_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
+ break;
+ case DW_CFA_val_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterIsExpression;
+ results->savedRegisters[reg].value = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_GNU_args_size:
+ offset = addressSpace.getULEB128(p, instructionsEnd);
+ results->spExtraArgSize = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
+ break;
+ case DW_CFA_GNU_negative_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = -offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
+ break;
+ default:
+ operand = opcode & 0x3F;
+ switch ( opcode & 0xC0 ) {
+ case DW_CFA_offset:
+ reg = operand;
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
+ break;
+ case DW_CFA_advance_loc:
+ codeOffset += operand * cieInfo.codeAlignFactor;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_restore:
+ // <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
+ // libffi uses DW_CFA_restore in the middle of some custom dward, so it is not a good epilog flag
+ //return true; // gcc-4.5 starts the epilog with this
+ reg = operand;
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
+ break;
+ default:
+ if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+} // namespace lldb_private
+
+
+#endif // __DWARF_PARSER_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp
new file mode 100644
index 00000000000..a4af02051a5
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp
@@ -0,0 +1,135 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- FileAbstraction.hpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __FILE_ABSTRACTION__
+#define __FILE_ABSTRACTION__
+
+
+#include <stdint.h>
+#include <string.h>
+#include <libkern/OSByteOrder.h>
+
+#ifdef __OPTIMIZE__
+#define INLINE __attribute__((always_inline))
+#else
+#define INLINE
+#endif
+
+//
+// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
+//
+// For example: to make a utility that handles 32-bit little enidan files use: Pointer32<LittleEndian>
+//
+//
+// get16() read a 16-bit number from an E endian struct
+// set16() write a 16-bit number to an E endian struct
+// get32() read a 32-bit number from an E endian struct
+// set32() write a 32-bit number to an E endian struct
+// get64() read a 64-bit number from an E endian struct
+// set64() write a 64-bit number to an E endian struct
+//
+// getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+// setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+//
+// getBitsRaw() read a bit field from a struct with native endianness
+// setBitsRaw() write a bit field from a struct with native endianness
+//
+
+class BigEndian
+{
+public:
+ static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); }
+ static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); }
+
+ static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
+ static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); }
+
+ static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
+ static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); }
+
+ static uint32_t getBits(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+ static void setBits(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+ static uint32_t getBitsRaw(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << (32-firstBit-bitCount));
+ temp |= ((value & mask) << (32-firstBit-bitCount));
+ into = temp; }
+ enum { little_endian = 0 };
+};
+
+
+class LittleEndian
+{
+public:
+ static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
+ static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
+
+ static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
+ static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
+
+ static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
+ static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&into, 0, value); }
+
+ static uint32_t getBits(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+ static void setBits(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+ static uint32_t getBitsRaw(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << firstBit);
+ temp |= ((value & mask) << firstBit);
+ into = temp; }
+ enum { little_endian = 1 };
+};
+
+
+template <typename _E>
+class Pointer32
+{
+public:
+ typedef uint32_t uint_t;
+ typedef int32_t int_t;
+ typedef _E E;
+
+ static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
+ static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); }
+};
+
+
+template <typename _E>
+class Pointer64
+{
+public:
+ typedef uint64_t uint_t;
+ typedef int64_t int_t;
+ typedef _E E;
+
+ static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
+ static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); }
+};
+
+
+
+
+
+
+#endif // __FILE_ABSTRACTION__
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h b/lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h
new file mode 100644
index 00000000000..40483900d38
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h
@@ -0,0 +1,89 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- InternalMacros.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INTERNAL_MACROS_H
+#define INTERNAL_MACROS_H
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn));
+#ifdef __cplusplus
+}
+#endif
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END 0
+
+
+struct v128 { unsigned int vec[4]; };
+
+
+#define EXPORT __attribute__((visibility("default")))
+
+#define COMPILE_TIME_ASSERT( expr ) \
+ extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) );
+
+#define ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg)
+
+#if NDEBUG
+ #define DEBUG_MESSAGE(msg, ...)
+ #define DEBUG_PRINT_API(msg, ...)
+ #define DEBUG_PRINT_UNWINDING_TEST 0
+ #define DEBUG_PRINT_UNWINDING(msg, ...)
+ #define DEBUG_LOG_NON_ZERO(x) x;
+ #define INITIALIZE_DEBUG_PRINT_API
+ #define INITIALIZE_DEBUG_PRINT_UNWINDING
+#else
+ #define DEBUG_MESSAGE(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ extern bool logAPIs();
+ extern bool logUnwinding();
+ #ifdef __cplusplus
+ }
+ #endif
+ #define DEBUG_LOG_NON_ZERO(x) { int _err = x; if ( _err != 0 ) fprintf(stderr, "libuwind: " #x "=%d in %s", _err, __FUNCTION__); }
+ #define DEBUG_PRINT_API(msg, ...) do { if ( logAPIs() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
+ #define DEBUG_PRINT_UNWINDING(msg, ...) do { if ( logUnwinding() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
+ #define DEBUG_PRINT_UNWINDING_TEST logUnwinding()
+ #define INITIALIZE_DEBUG_PRINT_API bool logAPIs() { static bool log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); return log; }
+ #define INITIALIZE_DEBUG_PRINT_UNWINDING bool logUnwinding() { static bool log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); return log; }
+#endif
+
+
+// note hack for <rdar://problem/6175741>
+// Once libgcc_s.dylib vectors to libSystem, then we can remove the $ld$hide$os10.6$ lines
+#if __ppc__
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#else
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
+
+
+
+#endif // INTERNAL_MACROS_H
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp
new file mode 100644
index 00000000000..291c72425d4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp
@@ -0,0 +1,985 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- Registers.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 __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach/ppc/thread_status.h>
+#include <mach/i386/thread_status.h>
+
+#include "libunwind.h"
+#include "InternalMacros.h"
+
+namespace lldb_private {
+
+
+///
+/// Registers_x86 holds the register state of a thread in a 32-bit intel process.
+///
+class Registers_x86
+{
+public:
+ Registers_x86();
+ Registers_x86(const void* registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const { return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char* getRegisterName(int num);
+ void jumpto() {}
+
+ uint32_t getSP() const { return fRegisters.__esp; }
+ void setSP(uint32_t value) { fRegisters.__esp = value; }
+ uint32_t getIP() const { return fRegisters.__eip; }
+ void setIP(uint32_t value) { fRegisters.__eip = value; }
+ uint32_t getEBP() const { return fRegisters.__ebp; }
+ void setEBP(uint32_t value) { fRegisters.__ebp = value; }
+ uint32_t getEBX() const { return fRegisters.__ebx; }
+ void setEBX(uint32_t value) { fRegisters.__ebx = value; }
+ uint32_t getECX() const { return fRegisters.__ecx; }
+ void setECX(uint32_t value) { fRegisters.__ecx = value; }
+ uint32_t getEDX() const { return fRegisters.__edx; }
+ void setEDX(uint32_t value) { fRegisters.__edx = value; }
+ uint32_t getESI() const { return fRegisters.__esi; }
+ void setESI(uint32_t value) { fRegisters.__esi = value; }
+ uint32_t getEDI() const { return fRegisters.__edi; }
+ void setEDI(uint32_t value) { fRegisters.__edi = value; }
+
+private:
+ i386_thread_state_t fRegisters;
+};
+
+inline Registers_x86::Registers_x86(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_x86) < sizeof(unw_context_t) );
+ fRegisters = *((i386_thread_state_t*)registers);
+}
+
+inline Registers_x86::Registers_x86()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+}
+
+
+inline bool Registers_x86::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum > 7 )
+ return false;
+ return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__eip;
+ case UNW_REG_SP:
+ return fRegisters.__esp;
+ case UNW_X86_EAX:
+ return fRegisters.__eax;
+ case UNW_X86_ECX:
+ return fRegisters.__ecx;
+ case UNW_X86_EDX:
+ return fRegisters.__edx;
+ case UNW_X86_EBX:
+ return fRegisters.__ebx;
+ case UNW_X86_EBP:
+ return fRegisters.__ebp;
+ case UNW_X86_ESP:
+ return fRegisters.__esp;
+ case UNW_X86_ESI:
+ return fRegisters.__esi;
+ case UNW_X86_EDI:
+ return fRegisters.__edi;
+ }
+ ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__eip = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__esp = value;
+ return;
+ case UNW_X86_EAX:
+ fRegisters.__eax = value;
+ return;
+ case UNW_X86_ECX:
+ fRegisters.__ecx = value;
+ return;
+ case UNW_X86_EDX:
+ fRegisters.__edx = value;
+ return;
+ case UNW_X86_EBX:
+ fRegisters.__ebx = value;
+ return;
+ case UNW_X86_EBP:
+ fRegisters.__ebp = value;
+ return;
+ case UNW_X86_ESP:
+ fRegisters.__esp = value;
+ return;
+ case UNW_X86_ESI:
+ fRegisters.__esi = value;
+ return;
+ case UNW_X86_EDI:
+ fRegisters.__edi = value;
+ return;
+ }
+ ABORT("unsupported x86 register");
+}
+
+inline const char* Registers_x86::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "esp";
+ case UNW_X86_EAX:
+ return "eax";
+ case UNW_X86_ECX:
+ return "ecx";
+ case UNW_X86_EDX:
+ return "edx";
+ case UNW_X86_EBX:
+ return "ebx";
+ case UNW_X86_EBP:
+ return "ebp";
+ case UNW_X86_ESP:
+ return "esp";
+ case UNW_X86_ESI:
+ return "esi";
+ case UNW_X86_EDI:
+ return "edi";
+ default:
+ return "unknown register";
+ }
+}
+
+inline double Registers_x86::getFloatRegister(int num) const
+{
+ ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int num, double value)
+{
+ ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int num) const
+{
+ ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int num, v128 value)
+{
+ ABORT("no x86 vector registers");
+}
+
+
+
+
+///
+/// Registers_x86_64 holds the register state of a thread in a 64-bit intel process.
+///
+class Registers_x86_64
+{
+public:
+ Registers_x86_64();
+ Registers_x86_64(const void* registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const{ return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char* getRegisterName(int num);
+ void jumpto() {}
+ uint64_t getSP() const { return fRegisters.__rsp; }
+ void setSP(uint64_t value) { fRegisters.__rsp = value; }
+ uint64_t getIP() const { return fRegisters.__rip; }
+ void setIP(uint64_t value) { fRegisters.__rip = value; }
+ uint64_t getRBP() const { return fRegisters.__rbp; }
+ void setRBP(uint64_t value) { fRegisters.__rbp = value; }
+ uint64_t getRBX() const { return fRegisters.__rbx; }
+ void setRBX(uint64_t value) { fRegisters.__rbx = value; }
+ uint64_t getR12() const { return fRegisters.__r12; }
+ void setR12(uint64_t value) { fRegisters.__r12 = value; }
+ uint64_t getR13() const { return fRegisters.__r13; }
+ void setR13(uint64_t value) { fRegisters.__r13 = value; }
+ uint64_t getR14() const { return fRegisters.__r14; }
+ void setR14(uint64_t value) { fRegisters.__r14 = value; }
+ uint64_t getR15() const { return fRegisters.__r15; }
+ void setR15(uint64_t value) { fRegisters.__r15 = value; }
+private:
+ x86_thread_state64_t fRegisters;
+};
+
+inline Registers_x86_64::Registers_x86_64(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_x86_64) < sizeof(unw_context_t) );
+ fRegisters = *((x86_thread_state64_t*)registers);
+}
+
+inline Registers_x86_64::Registers_x86_64()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+}
+
+
+inline bool Registers_x86_64::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum > 15 )
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__rip;
+ case UNW_REG_SP:
+ return fRegisters.__rsp;
+ case UNW_X86_64_RAX:
+ return fRegisters.__rax;
+ case UNW_X86_64_RDX:
+ return fRegisters.__rdx;
+ case UNW_X86_64_RCX:
+ return fRegisters.__rcx;
+ case UNW_X86_64_RBX:
+ return fRegisters.__rbx;
+ case UNW_X86_64_RSI:
+ return fRegisters.__rsi;
+ case UNW_X86_64_RDI:
+ return fRegisters.__rdi;
+ case UNW_X86_64_RBP:
+ return fRegisters.__rbp;
+ case UNW_X86_64_RSP:
+ return fRegisters.__rsp;
+ case UNW_X86_64_R8:
+ return fRegisters.__r8;
+ case UNW_X86_64_R9:
+ return fRegisters.__r9;
+ case UNW_X86_64_R10:
+ return fRegisters.__r10;
+ case UNW_X86_64_R11:
+ return fRegisters.__r11;
+ case UNW_X86_64_R12:
+ return fRegisters.__r12;
+ case UNW_X86_64_R13:
+ return fRegisters.__r13;
+ case UNW_X86_64_R14:
+ return fRegisters.__r14;
+ case UNW_X86_64_R15:
+ return fRegisters.__r15;
+ }
+ ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__rip = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__rsp = value;
+ return;
+ case UNW_X86_64_RAX:
+ fRegisters.__rax = value;
+ return;
+ case UNW_X86_64_RDX:
+ fRegisters.__rdx = value;
+ return;
+ case UNW_X86_64_RCX:
+ fRegisters.__rcx = value;
+ return;
+ case UNW_X86_64_RBX:
+ fRegisters.__rbx = value;
+ return;
+ case UNW_X86_64_RSI:
+ fRegisters.__rsi = value;
+ return;
+ case UNW_X86_64_RDI:
+ fRegisters.__rdi = value;
+ return;
+ case UNW_X86_64_RBP:
+ fRegisters.__rbp = value;
+ return;
+ case UNW_X86_64_RSP:
+ fRegisters.__rsp = value;
+ return;
+ case UNW_X86_64_R8:
+ fRegisters.__r8 = value;
+ return;
+ case UNW_X86_64_R9:
+ fRegisters.__r9 = value;
+ return;
+ case UNW_X86_64_R10:
+ fRegisters.__r10 = value;
+ return;
+ case UNW_X86_64_R11:
+ fRegisters.__r11 = value;
+ return;
+ case UNW_X86_64_R12:
+ fRegisters.__r12 = value;
+ return;
+ case UNW_X86_64_R13:
+ fRegisters.__r13 = value;
+ return;
+ case UNW_X86_64_R14:
+ fRegisters.__r14 = value;
+ return;
+ case UNW_X86_64_R15:
+ fRegisters.__r15 = value;
+ return;
+ }
+ ABORT("unsupported x86_64 register");
+}
+
+inline const char* Registers_x86_64::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "rip";
+ case UNW_REG_SP:
+ return "rsp";
+ case UNW_X86_64_RAX:
+ return "rax";
+ case UNW_X86_64_RDX:
+ return "rdx";
+ case UNW_X86_64_RCX:
+ return "rcx";
+ case UNW_X86_64_RBX:
+ return "rbx";
+ case UNW_X86_64_RSI:
+ return "rsi";
+ case UNW_X86_64_RDI:
+ return "rdi";
+ case UNW_X86_64_RBP:
+ return "rbp";
+ case UNW_X86_64_RSP:
+ return "rsp";
+ case UNW_X86_64_R8:
+ return "r8";
+ case UNW_X86_64_R9:
+ return "r9";
+ case UNW_X86_64_R10:
+ return "r10";
+ case UNW_X86_64_R11:
+ return "r11";
+ case UNW_X86_64_R12:
+ return "r12";
+ case UNW_X86_64_R13:
+ return "r13";
+ case UNW_X86_64_R14:
+ return "r14";
+ case UNW_X86_64_R15:
+ return "r15";
+ default:
+ return "unknown register";
+ }
+}
+
+double Registers_x86_64::getFloatRegister(int num) const
+{
+ ABORT("no x86_64 float registers");
+}
+
+void Registers_x86_64::setFloatRegister(int num, double value)
+{
+ ABORT("no x86_64 float registers");
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int num) const
+{
+ ABORT("no x86_64 vector registers");
+}
+
+inline void Registers_x86_64::setVectorRegister(int num, v128 value)
+{
+ ABORT("no x86_64 vector registers");
+}
+
+
+///
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC process.
+///
+class Registers_ppc
+{
+public:
+ Registers_ppc();
+ Registers_ppc(const void* registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ void jumpto() {}
+ const char* getRegisterName(int num);
+ uint64_t getSP() const { return fRegisters.__r1; }
+ void setSP(uint64_t value) { fRegisters.__r1 = value; }
+ uint64_t getIP() const { return fRegisters.__srr0; }
+ void setIP(uint64_t value) { fRegisters.__srr0 = value; }
+private:
+ ppc_thread_state_t fRegisters;
+ ppc_float_state_t fFloatRegisters;
+ v128 fVectorRegisters[32]; // offset 424
+};
+
+
+
+inline Registers_ppc::Registers_ppc(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_ppc) < sizeof(unw_context_t) );
+ fRegisters = *((ppc_thread_state_t*)registers);
+ fFloatRegisters = *((ppc_float_state_t*)((char*)registers+160));
+ memcpy(fVectorRegisters, ((char*)registers+424), sizeof(fVectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+ bzero(&fFloatRegisters, sizeof(fFloatRegisters));
+ bzero(&fVectorRegisters, sizeof(fVectorRegisters));
+}
+
+
+inline bool Registers_ppc::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum == UNW_PPC_VRSAVE )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum <= UNW_PPC_R31 )
+ return true;
+ if ( regNum == UNW_PPC_MQ )
+ return true;
+ if ( regNum == UNW_PPC_LR )
+ return true;
+ if ( regNum == UNW_PPC_CTR )
+ return true;
+ if ( (UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7) )
+ return true;
+ return false;
+}
+
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__srr0;
+ case UNW_REG_SP:
+ return fRegisters.__r1;
+ case UNW_PPC_R0:
+ return fRegisters.__r0;
+ case UNW_PPC_R1:
+ return fRegisters.__r1;
+ case UNW_PPC_R2:
+ return fRegisters.__r2;
+ case UNW_PPC_R3:
+ return fRegisters.__r3;
+ case UNW_PPC_R4:
+ return fRegisters.__r4;
+ case UNW_PPC_R5:
+ return fRegisters.__r5;
+ case UNW_PPC_R6:
+ return fRegisters.__r6;
+ case UNW_PPC_R7:
+ return fRegisters.__r7;
+ case UNW_PPC_R8:
+ return fRegisters.__r8;
+ case UNW_PPC_R9:
+ return fRegisters.__r9;
+ case UNW_PPC_R10:
+ return fRegisters.__r10;
+ case UNW_PPC_R11:
+ return fRegisters.__r11;
+ case UNW_PPC_R12:
+ return fRegisters.__r12;
+ case UNW_PPC_R13:
+ return fRegisters.__r13;
+ case UNW_PPC_R14:
+ return fRegisters.__r14;
+ case UNW_PPC_R15:
+ return fRegisters.__r15;
+ case UNW_PPC_R16:
+ return fRegisters.__r16;
+ case UNW_PPC_R17:
+ return fRegisters.__r17;
+ case UNW_PPC_R18:
+ return fRegisters.__r18;
+ case UNW_PPC_R19:
+ return fRegisters.__r19;
+ case UNW_PPC_R20:
+ return fRegisters.__r20;
+ case UNW_PPC_R21:
+ return fRegisters.__r21;
+ case UNW_PPC_R22:
+ return fRegisters.__r22;
+ case UNW_PPC_R23:
+ return fRegisters.__r23;
+ case UNW_PPC_R24:
+ return fRegisters.__r24;
+ case UNW_PPC_R25:
+ return fRegisters.__r25;
+ case UNW_PPC_R26:
+ return fRegisters.__r26;
+ case UNW_PPC_R27:
+ return fRegisters.__r27;
+ case UNW_PPC_R28:
+ return fRegisters.__r28;
+ case UNW_PPC_R29:
+ return fRegisters.__r29;
+ case UNW_PPC_R30:
+ return fRegisters.__r30;
+ case UNW_PPC_R31:
+ return fRegisters.__r31;
+ case UNW_PPC_LR:
+ return fRegisters.__lr;
+ case UNW_PPC_CR0:
+ return (fRegisters.__cr & 0xF0000000);
+ case UNW_PPC_CR1:
+ return (fRegisters.__cr & 0x0F000000);
+ case UNW_PPC_CR2:
+ return (fRegisters.__cr & 0x00F00000);
+ case UNW_PPC_CR3:
+ return (fRegisters.__cr & 0x000F0000);
+ case UNW_PPC_CR4:
+ return (fRegisters.__cr & 0x0000F000);
+ case UNW_PPC_CR5:
+ return (fRegisters.__cr & 0x00000F00);
+ case UNW_PPC_CR6:
+ return (fRegisters.__cr & 0x000000F0);
+ case UNW_PPC_CR7:
+ return (fRegisters.__cr & 0x0000000F);
+ case UNW_PPC_VRSAVE:
+ return fRegisters.__vrsave;
+ }
+ ABORT("unsupported ppc register");
+}
+
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value)
+{
+ //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__srr0 = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__r1 = value;
+ return;
+ case UNW_PPC_R0:
+ fRegisters.__r0 = value;
+ return;
+ case UNW_PPC_R1:
+ fRegisters.__r1 = value;
+ return;
+ case UNW_PPC_R2:
+ fRegisters.__r2 = value;
+ return;
+ case UNW_PPC_R3:
+ fRegisters.__r3 = value;
+ return;
+ case UNW_PPC_R4:
+ fRegisters.__r4 = value;
+ return;
+ case UNW_PPC_R5:
+ fRegisters.__r5 = value;
+ return;
+ case UNW_PPC_R6:
+ fRegisters.__r6 = value;
+ return;
+ case UNW_PPC_R7:
+ fRegisters.__r7 = value;
+ return;
+ case UNW_PPC_R8:
+ fRegisters.__r8 = value;
+ return;
+ case UNW_PPC_R9:
+ fRegisters.__r9 = value;
+ return;
+ case UNW_PPC_R10:
+ fRegisters.__r10 = value;
+ return;
+ case UNW_PPC_R11:
+ fRegisters.__r11 = value;
+ return;
+ case UNW_PPC_R12:
+ fRegisters.__r12 = value;
+ return;
+ case UNW_PPC_R13:
+ fRegisters.__r13 = value;
+ return;
+ case UNW_PPC_R14:
+ fRegisters.__r14 = value;
+ return;
+ case UNW_PPC_R15:
+ fRegisters.__r15 = value;
+ return;
+ case UNW_PPC_R16:
+ fRegisters.__r16 = value;
+ return;
+ case UNW_PPC_R17:
+ fRegisters.__r17 = value;
+ return;
+ case UNW_PPC_R18:
+ fRegisters.__r18 = value;
+ return;
+ case UNW_PPC_R19:
+ fRegisters.__r19 = value;
+ return;
+ case UNW_PPC_R20:
+ fRegisters.__r20 = value;
+ return;
+ case UNW_PPC_R21:
+ fRegisters.__r21 = value;
+ return;
+ case UNW_PPC_R22:
+ fRegisters.__r22 = value;
+ return;
+ case UNW_PPC_R23:
+ fRegisters.__r23 = value;
+ return;
+ case UNW_PPC_R24:
+ fRegisters.__r24 = value;
+ return;
+ case UNW_PPC_R25:
+ fRegisters.__r25 = value;
+ return;
+ case UNW_PPC_R26:
+ fRegisters.__r26 = value;
+ return;
+ case UNW_PPC_R27:
+ fRegisters.__r27 = value;
+ return;
+ case UNW_PPC_R28:
+ fRegisters.__r28 = value;
+ return;
+ case UNW_PPC_R29:
+ fRegisters.__r29 = value;
+ return;
+ case UNW_PPC_R30:
+ fRegisters.__r30 = value;
+ return;
+ case UNW_PPC_R31:
+ fRegisters.__r31 = value;
+ return;
+ case UNW_PPC_MQ:
+ fRegisters.__mq = value;
+ return;
+ case UNW_PPC_LR:
+ fRegisters.__lr = value;
+ return;
+ case UNW_PPC_CTR:
+ fRegisters.__ctr = value;
+ return;
+ case UNW_PPC_CR0:
+ fRegisters.__cr &= 0x0FFFFFFF;
+ fRegisters.__cr |= (value & 0xF0000000);
+ return;
+ case UNW_PPC_CR1:
+ fRegisters.__cr &= 0xF0FFFFFF;
+ fRegisters.__cr |= (value & 0x0F000000);
+ return;
+ case UNW_PPC_CR2:
+ fRegisters.__cr &= 0xFF0FFFFF;
+ fRegisters.__cr |= (value & 0x00F00000);
+ return;
+ case UNW_PPC_CR3:
+ fRegisters.__cr &= 0xFFF0FFFF;
+ fRegisters.__cr |= (value & 0x000F0000);
+ return;
+ case UNW_PPC_CR4:
+ fRegisters.__cr &= 0xFFFF0FFF;
+ fRegisters.__cr |= (value & 0x0000F000);
+ return;
+ case UNW_PPC_CR5:
+ fRegisters.__cr &= 0xFFFFF0FF;
+ fRegisters.__cr |= (value & 0x00000F00);
+ return;
+ case UNW_PPC_CR6:
+ fRegisters.__cr &= 0xFFFFFF0F;
+ fRegisters.__cr |= (value & 0x000000F0);
+ return;
+ case UNW_PPC_CR7:
+ fRegisters.__cr &= 0xFFFFFFF0;
+ fRegisters.__cr |= (value & 0x0000000F);
+ return;
+ case UNW_PPC_VRSAVE:
+ fRegisters.__vrsave = value;
+ return;
+ // not saved
+ return;
+ case UNW_PPC_XER:
+ fRegisters.__xer = value;
+ return;
+ case UNW_PPC_AP:
+ case UNW_PPC_VSCR:
+ case UNW_PPC_SPEFSCR:
+ // not saved
+ return;
+ }
+ ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const
+{
+ if ( regNum < UNW_PPC_F0 )
+ return false;
+ if ( regNum > UNW_PPC_F31 )
+ return false;
+ return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const
+{
+ assert(validFloatRegister(regNum));
+ return fFloatRegisters.__fpregs[regNum-UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value)
+{
+ //fprintf(stderr, "Registers_ppc::setFloatRegister(%d, %g))\n", regNum, value);
+ assert(validFloatRegister(regNum));
+ fFloatRegisters.__fpregs[regNum-UNW_PPC_F0] = value;
+}
+
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const
+{
+ if ( regNum < UNW_PPC_V0 )
+ return false;
+ if ( regNum > UNW_PPC_V31 )
+ return false;
+ return true;
+}
+
+v128 Registers_ppc::getVectorRegister(int regNum) const
+{
+ assert(validVectorRegister(regNum));
+ v128 result = fVectorRegisters[regNum-UNW_PPC_V0];
+ //fprintf(stderr, "Registers_ppc::getVectorRegister(this=%p, %d) => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
+ // this, regNum, result.vec[0], result.vec[1], result.vec[2], result.vec[3]);
+ return result;
+}
+
+void Registers_ppc::setVectorRegister(int regNum, v128 value)
+{
+ assert(validVectorRegister(regNum));
+ //fprintf(stderr, "Registers_ppc::setVectorRegister(this=%p, %d) <0x%08X, 0x%08X, 0x%08X, 0x%08X> => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
+ // this, regNum, fVectorRegisters[regNum-UNW_PPC_V0].vec[0], fVectorRegisters[regNum-UNW_PPC_V0].vec[1], fVectorRegisters[regNum-UNW_PPC_V0].vec[2],
+ // fVectorRegisters[regNum-UNW_PPC_V0].vec[3], value.vec[0], value.vec[1], value.vec[2], value.vec[3]);
+ fVectorRegisters[regNum-UNW_PPC_V0] = value;
+}
+
+
+inline const char* Registers_ppc::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_PPC_R0:
+ return "r0";
+ case UNW_PPC_R1:
+ return "r1";
+ case UNW_PPC_R2:
+ return "r2";
+ case UNW_PPC_R3:
+ return "r3";
+ case UNW_PPC_R4:
+ return "r4";
+ case UNW_PPC_R5:
+ return "r5";
+ case UNW_PPC_R6:
+ return "r6";
+ case UNW_PPC_R7:
+ return "r7";
+ case UNW_PPC_R8:
+ return "r8";
+ case UNW_PPC_R9:
+ return "r9";
+ case UNW_PPC_R10:
+ return "r10";
+ case UNW_PPC_R11:
+ return "r11";
+ case UNW_PPC_R12:
+ return "r12";
+ case UNW_PPC_R13:
+ return "r13";
+ case UNW_PPC_R14:
+ return "r14";
+ case UNW_PPC_R15:
+ return "r15";
+ case UNW_PPC_R16:
+ return "r16";
+ case UNW_PPC_R17:
+ return "r17";
+ case UNW_PPC_R18:
+ return "r18";
+ case UNW_PPC_R19:
+ return "r19";
+ case UNW_PPC_R20:
+ return "r20";
+ case UNW_PPC_R21:
+ return "r21";
+ case UNW_PPC_R22:
+ return "r22";
+ case UNW_PPC_R23:
+ return "r23";
+ case UNW_PPC_R24:
+ return "r24";
+ case UNW_PPC_R25:
+ return "r25";
+ case UNW_PPC_R26:
+ return "r26";
+ case UNW_PPC_R27:
+ return "r27";
+ case UNW_PPC_R28:
+ return "r28";
+ case UNW_PPC_R29:
+ return "r29";
+ case UNW_PPC_R30:
+ return "r30";
+ case UNW_PPC_R31:
+ return "r31";
+ case UNW_PPC_F0:
+ return "fp0";
+ case UNW_PPC_F1:
+ return "fp1";
+ case UNW_PPC_F2:
+ return "fp2";
+ case UNW_PPC_F3:
+ return "fp3";
+ case UNW_PPC_F4:
+ return "fp4";
+ case UNW_PPC_F5:
+ return "fp5";
+ case UNW_PPC_F6:
+ return "fp6";
+ case UNW_PPC_F7:
+ return "fp7";
+ case UNW_PPC_F8:
+ return "fp8";
+ case UNW_PPC_F9:
+ return "fp9";
+ case UNW_PPC_F10:
+ return "fp10";
+ case UNW_PPC_F11:
+ return "fp11";
+ case UNW_PPC_F12:
+ return "fp12";
+ case UNW_PPC_F13:
+ return "fp13";
+ case UNW_PPC_F14:
+ return "fp14";
+ case UNW_PPC_F15:
+ return "fp15";
+ case UNW_PPC_F16:
+ return "fp16";
+ case UNW_PPC_F17:
+ return "fp17";
+ case UNW_PPC_F18:
+ return "fp18";
+ case UNW_PPC_F19:
+ return "fp19";
+ case UNW_PPC_F20:
+ return "fp20";
+ case UNW_PPC_F21:
+ return "fp21";
+ case UNW_PPC_F22:
+ return "fp22";
+ case UNW_PPC_F23:
+ return "fp23";
+ case UNW_PPC_F24:
+ return "fp24";
+ case UNW_PPC_F25:
+ return "fp25";
+ case UNW_PPC_F26:
+ return "fp26";
+ case UNW_PPC_F27:
+ return "fp27";
+ case UNW_PPC_F28:
+ return "fp28";
+ case UNW_PPC_F29:
+ return "fp29";
+ case UNW_PPC_F30:
+ return "fp30";
+ case UNW_PPC_F31:
+ return "fp31";
+ case UNW_PPC_LR:
+ return "lr";
+ default:
+ return "unknown register";
+ }
+
+
+}
+
+
+} // namespace lldb_private
+
+
+
+#endif // __REGISTERS_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s
new file mode 100644
index 00000000000..45dae3bcbfc
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s
@@ -0,0 +1,261 @@
+
+
+#if __i386__
+ .text
+ .globl __ZN12lldb_private13Registers_x866jumptoEv
+ .private_extern __ZN12lldb_private13Registers_x866jumptoEv
+__ZN12lldb_private13Registers_x866jumptoEv:
+#
+# void lldb_private::Registers_x86::jumpto()
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+ movl 4(%esp), %eax
+ # set up eax and ret on new stack location
+ movl 28(%eax), %edx # edx holds new stack pointer
+ subl $8,%edx
+ movl %edx, 28(%eax)
+ movl 0(%eax), %ebx
+ movl %ebx, 0(%edx)
+ movl 40(%eax), %ebx
+ movl %ebx, 4(%edx)
+ # we now have ret and eax pushed onto where new stack will be
+ # restore all registers
+ movl 4(%eax), %ebx
+ movl 8(%eax), %ecx
+ movl 12(%eax), %edx
+ movl 16(%eax), %edi
+ movl 20(%eax), %esi
+ movl 24(%eax), %ebp
+ movl 28(%eax), %esp
+ # skip ss
+ # skip eflags
+ pop %eax # eax was already pushed on new stack
+ ret # eip was already pushed on new stack
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+
+#elif __x86_64__
+
+ .text
+ .globl __ZN12lldb_private16Registers_x86_646jumptoEv
+ .private_extern __ZN12lldb_private16Registers_x86_646jumptoEv
+__ZN12lldb_private16Registers_x86_646jumptoEv:
+#
+# void lldb_private::Registers_x86_64::jumpto()
+#
+# On entry, thread_state pointer is in rdi
+
+ movq 56(%rdi), %rax # rax holds new stack pointer
+ subq $16, %rax
+ movq %rax, 56(%rdi)
+ movq 32(%rdi), %rbx # store new rdi on new stack
+ movq %rbx, 0(%rax)
+ movq 128(%rdi), %rbx # store new rip on new stack
+ movq %rbx, 8(%rax)
+ # restore all registers
+ movq 0(%rdi), %rax
+ movq 8(%rdi), %rbx
+ movq 16(%rdi), %rcx
+ movq 24(%rdi), %rdx
+ # restore rdi later
+ movq 40(%rdi), %rsi
+ movq 48(%rdi), %rbp
+ # restore rsp later
+ movq 64(%rdi), %r8
+ movq 72(%rdi), %r9
+ movq 80(%rdi), %r10
+ movq 88(%rdi), %r11
+ movq 96(%rdi), %r12
+ movq 104(%rdi), %r13
+ movq 112(%rdi), %r14
+ movq 120(%rdi), %r15
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ movq 56(%rdi), %rsp # cut back rsp to new location
+ pop %rdi # rdi was saved here earlier
+ ret # rip was saved here
+
+
+#elif __ppc__
+
+ .text
+ .globl __ZN12lldb_private13Registers_ppc6jumptoEv
+ .private_extern __ZN12lldb_private13Registers_ppc6jumptoEv
+__ZN12lldb_private13Registers_ppc6jumptoEv:
+;
+; void lldb_private::Registers_ppc::jumpto()
+;
+; On entry:
+; thread_state pointer is in r3
+;
+
+ ; restore integral registerrs
+ ; skip r0 for now
+ ; skip r1 for now
+ lwz r2, 16(r3)
+ ; skip r3 for now
+ ; skip r4 for now
+ ; skip r5 for now
+ lwz r6, 32(r3)
+ lwz r7, 36(r3)
+ lwz r8, 40(r3)
+ lwz r9, 44(r3)
+ lwz r10, 48(r3)
+ lwz r11, 52(r3)
+ lwz r12, 56(r3)
+ lwz r13, 60(r3)
+ lwz r14, 64(r3)
+ lwz r15, 68(r3)
+ lwz r16, 72(r3)
+ lwz r17, 76(r3)
+ lwz r18, 80(r3)
+ lwz r19, 84(r3)
+ lwz r20, 88(r3)
+ lwz r21, 92(r3)
+ lwz r22, 96(r3)
+ lwz r23,100(r3)
+ lwz r24,104(r3)
+ lwz r25,108(r3)
+ lwz r26,112(r3)
+ lwz r27,116(r3)
+ lwz r28,120(r3)
+ lwz r29,124(r3)
+ lwz r30,128(r3)
+ lwz r31,132(r3)
+
+ ; restore float registers
+ lfd f0, 160(r3)
+ lfd f1, 168(r3)
+ lfd f2, 176(r3)
+ lfd f3, 184(r3)
+ lfd f4, 192(r3)
+ lfd f5, 200(r3)
+ lfd f6, 208(r3)
+ lfd f7, 216(r3)
+ lfd f8, 224(r3)
+ lfd f9, 232(r3)
+ lfd f10,240(r3)
+ lfd f11,248(r3)
+ lfd f12,256(r3)
+ lfd f13,264(r3)
+ lfd f14,272(r3)
+ lfd f15,280(r3)
+ lfd f16,288(r3)
+ lfd f17,296(r3)
+ lfd f18,304(r3)
+ lfd f19,312(r3)
+ lfd f20,320(r3)
+ lfd f21,328(r3)
+ lfd f22,336(r3)
+ lfd f23,344(r3)
+ lfd f24,352(r3)
+ lfd f25,360(r3)
+ lfd f26,368(r3)
+ lfd f27,376(r3)
+ lfd f28,384(r3)
+ lfd f29,392(r3)
+ lfd f30,400(r3)
+ lfd f31,408(r3)
+
+ ; restore vector registers if any are in use
+ lwz r5,156(r3) ; test VRsave
+ cmpwi r5,0
+ beq Lnovec
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+ ; the fVectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
+
+
+#define LOAD_VECTOR_UNALIGNEDl(_index) \
+ andis. r0,r5,(1<<(15-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+Ldone ## _index:
+
+#define LOAD_VECTOR_UNALIGNEDh(_index) \
+ andi. r0,r5,(1<<(31-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+ Ldone ## _index:
+
+
+ LOAD_VECTOR_UNALIGNEDl(0)
+ LOAD_VECTOR_UNALIGNEDl(1)
+ LOAD_VECTOR_UNALIGNEDl(2)
+ LOAD_VECTOR_UNALIGNEDl(3)
+ LOAD_VECTOR_UNALIGNEDl(4)
+ LOAD_VECTOR_UNALIGNEDl(5)
+ LOAD_VECTOR_UNALIGNEDl(6)
+ LOAD_VECTOR_UNALIGNEDl(7)
+ LOAD_VECTOR_UNALIGNEDl(8)
+ LOAD_VECTOR_UNALIGNEDl(9)
+ LOAD_VECTOR_UNALIGNEDl(10)
+ LOAD_VECTOR_UNALIGNEDl(11)
+ LOAD_VECTOR_UNALIGNEDl(12)
+ LOAD_VECTOR_UNALIGNEDl(13)
+ LOAD_VECTOR_UNALIGNEDl(14)
+ LOAD_VECTOR_UNALIGNEDl(15)
+ LOAD_VECTOR_UNALIGNEDh(16)
+ LOAD_VECTOR_UNALIGNEDh(17)
+ LOAD_VECTOR_UNALIGNEDh(18)
+ LOAD_VECTOR_UNALIGNEDh(19)
+ LOAD_VECTOR_UNALIGNEDh(20)
+ LOAD_VECTOR_UNALIGNEDh(21)
+ LOAD_VECTOR_UNALIGNEDh(22)
+ LOAD_VECTOR_UNALIGNEDh(23)
+ LOAD_VECTOR_UNALIGNEDh(24)
+ LOAD_VECTOR_UNALIGNEDh(25)
+ LOAD_VECTOR_UNALIGNEDh(26)
+ LOAD_VECTOR_UNALIGNEDh(27)
+ LOAD_VECTOR_UNALIGNEDh(28)
+ LOAD_VECTOR_UNALIGNEDh(29)
+ LOAD_VECTOR_UNALIGNEDh(30)
+ LOAD_VECTOR_UNALIGNEDh(31)
+
+Lnovec:
+ lwz r0, 136(r3) ; __cr
+ mtocrf 255,r0
+ lwz r0, 148(r3) ; __ctr
+ mtctr r0
+ lwz r0, 0(r3) ; __ssr0
+ mtctr r0
+ lwz r0, 8(r3) ; do r0 now
+ lwz r5,28(r3) ; do r5 now
+ lwz r4,24(r3) ; do r4 now
+ lwz r1,12(r3) ; do sp now
+ lwz r3,20(r3) ; do r3 last
+ bctr
+
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp
new file mode 100644
index 00000000000..1db3faffd10
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp
@@ -0,0 +1,88 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteDebuggerDummyUnwinder.hpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Code to unwind past a debugger's dummy frame inserted when it does an
+// inferior function call.
+// In this case we'll need to get the saved register context from the debugger -
+// it may be in the debugger's local memory or it may be saved in a nonstandard
+// location in the inferior process' memory.
+
+#ifndef __REMOTE_DEBUGGER_DUMMY_UNWINDER_HPP__
+#define __REMOTE_DEBUGGER_DUMMY_UNWINDER_HPP__
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include "libunwind.h"
+#include "Registers.hpp"
+#include "AddressSpace.hpp"
+#include "RemoteRegisterMap.hpp"
+#include "RemoteProcInfo.hpp"
+
+namespace lldb_private
+{
+
+template <typename A>
+int stepOutOfDebuggerDummyFrame (A& addressSpace, Registers_x86_64& registers,
+ RemoteProcInfo *procinfo, uint64_t ip,
+ uint64_t sp, void* arg)
+{
+ Registers_x86_64 newRegisters(registers);
+ RemoteRegisterMap *rmap = addressSpace.getRemoteProcInfo()->getRegisterMap();
+ unw_word_t regv;
+ for (int i = UNW_X86_64_RAX; i <= UNW_X86_64_R15; i++) {
+ int driver_regnum;
+ if (!rmap->unwind_regno_to_caller_regno (i, driver_regnum))
+ continue;
+ if (addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, driver_regnum, &regv, 0, arg))
+ newRegisters.setRegister(i, regv);
+ }
+ if (!addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, rmap->caller_regno_for_ip(), &regv, 0, arg))
+ return UNW_EUNSPEC;
+ newRegisters.setIP (regv);
+ registers = newRegisters;
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int stepOutOfDebuggerDummyFrame (A& addressSpace, Registers_x86& registers,
+ RemoteProcInfo *procinfo, uint64_t ip,
+ uint64_t sp, void* arg)
+{
+ Registers_x86 newRegisters(registers);
+ RemoteRegisterMap *rmap = addressSpace.getRemoteProcInfo()->getRegisterMap();
+ unw_word_t regv;
+ for (int i = UNW_X86_EAX; i <= UNW_X86_EDI; i++) {
+ int driver_regnum;
+ if (!rmap->unwind_regno_to_caller_regno (i, driver_regnum))
+ continue;
+ if (addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, driver_regnum, &regv, 0, arg))
+ newRegisters.setRegister(i, regv);
+ }
+ if (!addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, rmap->caller_regno_for_ip(), &regv, 0, arg))
+ return UNW_EUNSPEC;
+ newRegisters.setIP (regv);
+ registers = newRegisters;
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int stepOutOfDebuggerDummyFrame (A& addressSpace, Registers_ppc& registers,
+ uint64_t ip, uint64_t sp)
+{
+ ABORT ("stepping out of a debugger dummy frame not supported on ppc");
+ return UNW_EUNSPEC;
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+#endif // __REMOTE_DEBUGGER_DUMMY_UNWINDER_HPP__
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp
new file mode 100644
index 00000000000..3640dc6195c
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp
@@ -0,0 +1,977 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteProcInfo.hpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This file defines the primary object created when unw_create_addr_space()
+// is called. This object tracks the list of known images in memory
+// (dylibs, bundles, etc), it maintains a link to a RemoteRegisterMap for this
+// architecture, it caches the remote process memory in a local store and all
+// read/writes are filtered through its accessors which will use the memory
+// caches. It maintains a logging level set by the driver program and puts
+// timing/debug messages out on a FILE* provided to it.
+
+// RemoteProcInfo is not specific to any particular unwind so it does not
+// maintain an "arg" argument (an opaque pointer that the driver program uses
+// to track the process/thread being unwound).
+
+#ifndef __REMOTE_PROC_INFO_HPP__
+#define __REMOTE_PROC_INFO_HPP__
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach/ppc/thread_status.h>
+#include <mach/i386/thread_status.h>
+#include <Availability.h>
+
+#include <map>
+#include <vector>
+#include <algorithm>
+
+#include "FileAbstraction.hpp"
+#include "libunwind.h"
+#include "InternalMacros.h"
+#include "dwarf2.h"
+#include "RemoteUnwindProfile.h"
+#include "Registers.hpp"
+#include "RemoteRegisterMap.hpp"
+
+namespace lldb_private
+{
+class RemoteProcInfo;
+
+///
+/// unw_addr_space_remote is the concrete instance that a unw_addr_space_t points to when examining
+/// a remote process.
+///
+struct unw_addr_space_remote
+{
+ enum unw_as_type type; // should always be UNW_REMOTE
+ RemoteProcInfo* ras;
+};
+
+class RemoteMemoryBlob
+{
+public:
+ typedef void (*free_callback_with_arg)(void *, void*);
+ typedef void (*free_callback)(void *);
+
+ /* This object is constructed with a callback to free the memory;
+ that callback takes a pointer to the memory region and optionally
+ takes an additional argument -- the "void* arg" passed around for
+ remote unwinds, in case the driver program allocated this e.g. with
+ mach_vm_read, and needs the token to vm_deallocate it. */
+
+ RemoteMemoryBlob (uint8_t *buf, free_callback_with_arg to_free,
+ uint64_t startaddr, uint64_t len, uint64_t mh, void *arg) :
+ fBuf(buf), fToFreeWithArg(to_free), fToFree(NULL),
+ fStartAddr(startaddr), fLen(len), fMachHeader(mh),
+ fArg(arg) { }
+ RemoteMemoryBlob (uint8_t *buf, free_callback to_free, uint64_t startaddr,
+ uint64_t len, uint64_t mh, void *arg) :
+ fBuf(buf), fToFree(to_free), fToFreeWithArg(NULL),
+ fStartAddr(startaddr), fLen(len), fMachHeader(mh),
+ fArg(NULL) { }
+
+ // the following is to create a dummy RMB object for lower_bound's use in
+ // searching.
+ RemoteMemoryBlob (uint64_t startaddr) : fStartAddr(startaddr), fToFree(NULL),
+ fBuf(NULL), fToFreeWithArg(NULL), fArg(NULL), fMachHeader(-1),
+ fLen(0) { }
+ ~RemoteMemoryBlob () {
+ if (fToFreeWithArg)
+ fToFreeWithArg(fBuf, fArg);
+ else if (fToFree)
+ fToFree(fBuf);
+ }
+ bool contains_addr (uint64_t addr) {
+ if (fStartAddr <= addr && addr < fStartAddr + fLen)
+ return true;
+ else
+ return false;
+ }
+ uint8_t *get_blob_range (uint64_t remote_process_addr, int len) {
+ if (this->contains_addr (remote_process_addr) == false)
+ return NULL;
+ if (this->contains_addr (remote_process_addr + len) == false)
+ return NULL;
+ return fBuf + (remote_process_addr - fStartAddr);
+ }
+ uint64_t getMh () const { return fMachHeader; }
+ uint64_t getStartAddr() const { return fStartAddr; }
+ uint64_t getLength() const { return fLen; }
+private:
+ uint8_t *fBuf;
+ free_callback fToFree;
+ free_callback_with_arg fToFreeWithArg;
+ uint64_t fStartAddr;
+ uint64_t fLen;
+ uint64_t fMachHeader;
+ void *fArg;
+};
+
+inline bool operator<(const RemoteMemoryBlob &b1, const RemoteMemoryBlob &b2) {
+ if (b1.getStartAddr() < b2.getStartAddr())
+ return true;
+ else
+ return false;
+}
+
+// One of these for each image in memory (executable, dylib, bundle, etc)
+
+struct RemoteImageEntry
+{
+ RemoteImageEntry () : mach_header(0), text_start(0), text_end(0), eh_frame_start(0), eh_frame_len(0), compact_unwind_info_start(0), compact_unwind_info_len(0) { }
+ ~RemoteImageEntry () {
+ std::map<uint64_t, RemoteUnwindProfile *>::iterator i;
+ for (i = profiles.begin(); i != profiles.end(); ++i)
+ delete i->second;
+ }
+ uint64_t mach_header;
+ uint64_t text_start;
+ uint64_t text_end;
+ uint64_t eh_frame_start;
+ uint64_t eh_frame_len;
+ uint64_t compact_unwind_info_start;
+ uint64_t compact_unwind_info_len;
+
+ // unwind profiles created for thsi binary image so far,
+ // key is the start address of the profile.
+ std::map<uint64_t, RemoteUnwindProfile *> profiles;
+
+ // a list of function address bounds for this binary image -
+ // end addresses should be accurate and not inferred from potentially
+ // incomplete start-address data (e.g. nlist records).
+ std::vector<FuncBounds> func_bounds;
+};
+
+class RemoteImages
+{
+public:
+ RemoteImages (unw_targettype_t targarch) : fTargetArch(targarch) { }
+ ~RemoteImages ();
+ void removeAllImageProfiles();
+ void removeOneImageProfiles(uint64_t mh);
+ RemoteImageEntry *remoteEntryForTextAddr (uint64_t pc);
+ bool addFuncBounds (uint64_t mh, std::vector<FuncBounds> &startAddrs);
+ bool haveFuncBounds (uint64_t mh);
+ bool findFuncBounds (uint32_t pc, uint32_t &startAddr, uint32_t &endAddr);
+ bool findFuncBounds (uint64_t pc, uint64_t &startAddr, uint64_t &endAddr);
+ void addImage (uint64_t mh, uint64_t text_start, uint64_t text_end, uint64_t eh_frame, uint64_t eh_frame_len, uint64_t compact_unwind_start, uint64_t compact_unwind_len);
+ bool addProfile (RemoteProcInfo* procinfo, unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, void *arg);
+ RemoteUnwindProfile* findProfileByTextAddr (uint64_t pc);
+ void addMemBlob (RemoteMemoryBlob *blob);
+ uint8_t *getMemBlobMemory (uint64_t addr, int len);
+private:
+ RemoteImages();
+ std::map<uint64_t, RemoteImageEntry> fImages;
+ std::vector<RemoteMemoryBlob *> fMemBlobs;
+ unw_targettype_t fTargetArch;
+};
+
+RemoteImages::~RemoteImages () {
+ std::map<uint64_t, std::vector<RemoteMemoryBlob *> >::iterator i;
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j) {
+ delete *j;
+ }
+ fMemBlobs.erase(fMemBlobs.begin(), fMemBlobs.end());
+}
+
+void RemoteImages::removeAllImageProfiles() {
+ fImages.erase(fImages.begin(), fImages.end());
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j)
+ delete *j;
+ fMemBlobs.erase(fMemBlobs.begin(), fMemBlobs.end());
+}
+
+void RemoteImages::removeOneImageProfiles(uint64_t mh) {
+ std::map<uint64_t, RemoteImageEntry>::iterator i;
+ i = fImages.find(mh);
+ if (i != fImages.end())
+ fImages.erase(i);
+
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j) {
+ if ((*j)->getMh() == mh) {
+ delete *j;
+ break;
+ }
+ }
+ if (j != fMemBlobs.end())
+ fMemBlobs.erase(j);
+}
+
+RemoteImageEntry *RemoteImages::remoteEntryForTextAddr (uint64_t pc) {
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (pc);
+ if (i == fImages.begin() && i == fImages.end())
+ return NULL;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != pc)
+ --i;
+ }
+ if (i->second.text_start <= pc && i->second.text_end > pc)
+ {
+ return &(i->second);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+bool RemoteImages::addFuncBounds (uint64_t mh, std::vector<FuncBounds> &startAddrs) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.find (mh);
+ if (i == fImages.end())
+ return false;
+ img = &i->second;
+ img->func_bounds = startAddrs;
+ std::sort(img->func_bounds.begin(), img->func_bounds.end());
+ return true;
+}
+
+bool RemoteImages::haveFuncBounds (uint64_t mh) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.find (mh);
+ if (i == fImages.end())
+ return false;
+ img = &i->second;
+ if (img->func_bounds.size() > 0)
+ return true;
+ return false;
+}
+
+bool RemoteImages::findFuncBounds (uint64_t pc, uint64_t &startAddr, uint64_t &endAddr) {
+ RemoteImageEntry *img = NULL;
+ startAddr = endAddr = 0;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (pc);
+ if (i == fImages.begin() && i == fImages.end())
+ return false;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != pc)
+ --i;
+ }
+ if (i->second.text_start <= pc && i->second.text_end > pc)
+ {
+ img = &i->second;
+ }
+ else
+ return false;
+ std::vector<FuncBounds>::iterator j;
+ j = std::lower_bound(img->func_bounds.begin(), img->func_bounds.end(), FuncBounds (pc, pc));
+ if (j == img->func_bounds.begin() && j == img->func_bounds.end())
+ return false;
+ if (j == img->func_bounds.end()) {
+ --j;
+ } else {
+ if (j != img->func_bounds.begin() && j->fStart != pc)
+ --j;
+ }
+ if (j->fStart <= pc && j->fEnd > pc) {
+ startAddr = j->fStart;
+ endAddr = j->fEnd;
+ return true;
+ }
+ return false;
+}
+
+// Add 32-bit version of findFuncBounds so we can avoid templatizing all of these functions
+// just to handle 64 and 32 bit unwinds.
+
+bool RemoteImages::findFuncBounds (uint32_t pc, uint32_t &startAddr, uint32_t &endAddr) {
+ uint64_t big_startAddr = startAddr;
+ uint64_t big_endAddr = endAddr;
+ bool ret;
+ ret = findFuncBounds (pc, big_startAddr, big_endAddr);
+ startAddr = (uint32_t) big_startAddr & 0xffffffff;
+ endAddr = (uint32_t) big_endAddr & 0xffffffff;
+ return ret;
+}
+
+// Make sure we don't cache the same memory range more than once
+// I'm not checking the length of the blobs to check for overlap -
+// as this is used today, the only duplication will be with the same
+// start address.
+
+void RemoteImages::addMemBlob (RemoteMemoryBlob *blob) {
+ std::vector<RemoteMemoryBlob *>::iterator i;
+ for (i = fMemBlobs.begin(); i != fMemBlobs.end(); ++i) {
+ if (blob->getStartAddr() == (*i)->getStartAddr())
+ return;
+ }
+ fMemBlobs.push_back(blob);
+ std::sort(fMemBlobs.begin(), fMemBlobs.end());
+}
+
+uint8_t *RemoteImages::getMemBlobMemory (uint64_t addr, int len) {
+ uint8_t *res = NULL;
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ RemoteMemoryBlob *searchobj = new RemoteMemoryBlob(addr);
+ j = std::lower_bound (fMemBlobs.begin(), fMemBlobs.end(), searchobj);
+ delete searchobj;
+ if (j == fMemBlobs.end() && j == fMemBlobs.begin())
+ return NULL;
+ if (j == fMemBlobs.end()) {
+ --j;
+ } else {
+ if (j != fMemBlobs.begin() && (*j)->getStartAddr() != addr)
+ --j;
+ }
+ res = (*j)->get_blob_range (addr, len);
+ if (res != NULL)
+ return res;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j) {
+ res = (*j)->get_blob_range (addr, len);
+ if (res != NULL)
+ break;
+ }
+ return res;
+}
+
+void RemoteImages::addImage (uint64_t mh, uint64_t text_start,
+ uint64_t text_end, uint64_t eh_frame,
+ uint64_t eh_frame_len,
+ uint64_t compact_unwind_start,
+ uint64_t compact_unwind_len) {
+ struct RemoteImageEntry img;
+ img.mach_header = mh;
+ img.text_start = text_start;
+ img.text_end = text_end;
+ img.eh_frame_start = eh_frame;
+ img.eh_frame_len = eh_frame_len;
+ img.compact_unwind_info_start = compact_unwind_start;
+ img.compact_unwind_info_len = compact_unwind_len;
+ fImages[mh] = img;
+}
+
+// The binary image for this start/end address must already be present
+bool RemoteImages::addProfile (RemoteProcInfo* procinfo, unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, void *arg) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (start);
+ if (i == fImages.begin() && i == fImages.end())
+ return false;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != start) {
+ --i;
+ }
+ }
+ if (i->second.text_start <= start && i->second.text_end > start)
+ {
+ img = &i->second;
+ }
+ else
+ return false;
+ RemoteUnwindProfile* profile = new RemoteUnwindProfile;
+ if (AssemblyParse (procinfo, acc, as, start, end, *profile, arg)) {
+ img->profiles[start] = profile;
+ return true;
+ }
+ return false;
+}
+
+RemoteUnwindProfile* RemoteImages::findProfileByTextAddr (uint64_t pc) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (pc);
+ if (i == fImages.begin() && i == fImages.end())
+ return NULL;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != pc)
+ --i;
+ }
+ if (i->second.text_start <= pc && i->second.text_end > pc)
+ {
+ img = &i->second;
+ }
+ else
+ return false;
+ std::map<uint64_t, RemoteUnwindProfile *>::iterator j;
+ j = img->profiles.lower_bound (pc);
+ if (j == img->profiles.begin() && j == img->profiles.end())
+ return NULL;
+ if (j == img->profiles.end()) {
+ --j;
+ } else {
+ if (j != img->profiles.begin() && j->first != pc)
+ --j;
+ }
+ if (j->second->fStart <= pc && j->second->fEnd > pc)
+ {
+ return j->second;
+ }
+ return NULL;
+}
+
+///
+/// RemoteProcInfo is used as a template parameter to UnwindCursor when
+/// unwinding a thread that has a custom set of accessors. It calls the
+/// custom accessors for all data.
+///
+class RemoteProcInfo
+{
+public:
+
+// libunwind documentation specifies that unw_create_addr_space defaults to
+// UNW_CACHE_NONE but that's going to work very poorly for us so we're
+// defaulting to UNW_CACHE_GLOBAL.
+
+ RemoteProcInfo(unw_accessors_t* accessors, unw_targettype_t targarch) :
+ fAccessors(*accessors), fCachingPolicy(UNW_CACHE_GLOBAL),
+ fTargetArch(targarch), fImages(targarch), fLogging(NULL),
+ fLogLevel(UNW_LOG_LEVEL_NONE)
+ {
+ fWrapper.type = UNW_REMOTE;
+ fWrapper.ras = this;
+ fRemoteRegisterMap = new RemoteRegisterMap(accessors, targarch);
+ if (fTargetArch == UNW_TARGET_X86_64 || fTargetArch == UNW_TARGET_I386
+ || fTargetArch == UNW_TARGET_ARM)
+ fLittleEndian = true;
+ else
+ fLittleEndian = false;
+ }
+
+ ~RemoteProcInfo () {
+ delete fRemoteRegisterMap;
+ }
+
+ bool haveProfile (uint64_t pc) {
+ if (fImages.findProfileByTextAddr (pc))
+ return true;
+ else
+ return false;
+ }
+
+ // returns NULL if profile does not yet exist.
+ RemoteUnwindProfile* findProfile (uint64_t pc) {
+ return fImages.findProfileByTextAddr (pc);
+ }
+
+ // returns NULL if the binary image is not yet added.
+ bool addProfile (unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, void *arg) {
+ if (fImages.addProfile (this, acc, as, start, end, arg))
+ return true;
+ else
+ return false;
+ }
+
+ bool haveImageEntry (uint64_t pc, void *arg);
+
+ bool getImageAddresses (uint64_t pc, uint64_t &mh, uint64_t &text_start, uint64_t &text_end,
+ uint64_t &eh_frame_start, uint64_t &eh_frame_len, uint64_t &compact_unwind_start,
+ void *arg);
+ bool getImageAddresses (uint64_t pc, uint32_t &mh, uint32_t &text_start, uint32_t &text_end,
+ uint32_t &eh_frame_start, uint32_t &eh_frame_len, uint32_t &compact_unwind_start,
+ void *arg);
+
+ bool addFuncBounds (uint64_t mh, std::vector<FuncBounds> &startAddrs) { return fImages.addFuncBounds (mh, startAddrs); }
+ bool haveFuncBounds (uint64_t mh) { return fImages.haveFuncBounds (mh); }
+ bool findStartAddr (uint64_t pc, uint32_t &startAddr, uint32_t &endAddr) { return fImages.findFuncBounds (pc, startAddr, endAddr); }
+ bool findStartAddr (uint64_t pc, uint64_t &startAddr, uint64_t &endAddr) { return fImages.findFuncBounds (pc, startAddr, endAddr); }
+ uint8_t *getMemBlobMemory (uint64_t addr, int len) { return fImages.getMemBlobMemory (addr, len); }
+
+
+ // Functions to pull memory from the target into the debugger.
+
+ int getBytes(uint64_t addr, uint64_t extent, uint8_t* buf, void* arg)
+ {
+ int err = readRaw(addr, extent, buf, arg);
+
+ if(err)
+ return 0;
+
+ return 1;
+ }
+
+#define DECLARE_INT_ACCESSOR(bits) \
+ uint##bits##_t get##bits(uint64_t addr, void* arg) \
+ { \
+ uint##bits##_t ret; \
+ int err = readRaw(addr, (unw_word_t)(bits / 8), (uint8_t*)&ret, arg); \
+ \
+ if(err) \
+ ABORT("Invalid memory access in the target"); \
+ \
+ return ret; \
+ }
+ DECLARE_INT_ACCESSOR(8)
+ DECLARE_INT_ACCESSOR(16)
+ DECLARE_INT_ACCESSOR(32)
+ DECLARE_INT_ACCESSOR(64)
+#undef DECLARE_INT_ACCESSOR
+
+// 'err' is set to 0 if there were no errors reading this
+// memory. Non-zero values indicate that the memory was not
+// read successfully. This method should be preferred over the
+// method above which asserts on failure.
+
+#define DECLARE_INT_ACCESSOR_ERR(bits) \
+ uint##bits##_t get##bits(uint64_t addr, int &err, void* arg) \
+ { \
+ uint##bits##_t ret; \
+ err = readRaw(addr, (unw_word_t)(bits / 8), (uint8_t*)&ret, arg); \
+ \
+ return ret; \
+ }
+ DECLARE_INT_ACCESSOR_ERR(8)
+ DECLARE_INT_ACCESSOR_ERR(16)
+ DECLARE_INT_ACCESSOR_ERR(32)
+ DECLARE_INT_ACCESSOR_ERR(64)
+#undef DECLARE_INT_ACCESSOR_ERR
+
+ double getDouble(uint64_t addr, void* arg)
+ {
+ double ret;
+ int err = readRaw(addr, (unw_word_t)(sizeof(ret) / 8), (uint8_t*)&ret, arg);
+ if(err)
+ ABORT("Invalid memory access in the target");
+ return ret;
+ }
+
+ v128 getVector(uint64_t addr, void* arg)
+ {
+ v128 ret;
+ int err = readRaw(addr, (unw_word_t)(sizeof(ret) / 8), (uint8_t*)&ret, arg);
+ if(err)
+ ABORT("Invalid memory access in the target");
+ return ret;
+ }
+
+ // Pull an unsigned LEB128 from the target into the debugger as a uint64_t.
+ uint64_t getULEB128(uint64_t& addr, uint64_t end, void* arg)
+ {
+ uint64_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ addr = lAddr;
+ return ret;
+ }
+
+ // Pull an unsigned LEB128 from the target into the debugger as a uint64_t.
+ uint64_t getULEB128(uint32_t& addr, uint32_t end, void* arg)
+ {
+ uint32_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ addr = lAddr;
+ return ret;
+ }
+
+
+ // Pull a signed LEB128 from the target into the debugger as a uint64_t.
+ int64_t getSLEB128(uint64_t& addr, uint64_t end, void* arg)
+ {
+ uint64_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ // Sign-extend
+ if((shift < (sizeof(int64_t) * 8)) && (byte & 0x40))
+ ret |= -(1 << shift);
+ addr = lAddr;
+ return ret;
+ }
+
+ // Pull a signed LEB128 from the target into the debugger as a uint64_t.
+ int64_t getSLEB128(uint32_t& addr, uint32_t end, void* arg)
+ {
+ uint32_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ // Sign-extend
+ if((shift < (sizeof(int64_t) * 8)) && (byte & 0x40))
+ ret |= -(1 << shift);
+ addr = lAddr;
+ return ret;
+ }
+
+
+ uint64_t getP (uint64_t addr, void *arg) {
+ switch (fTargetArch) {
+ case UNW_TARGET_X86_64:
+ return get64(addr, arg);
+ break;
+ case UNW_TARGET_I386:
+ return get32(addr, arg);
+ break;
+ }
+ ABORT("Unknown target architecture.");
+ return 0;
+ }
+
+ uint64_t getP (uint64_t addr, int& err, void *arg) {
+ switch (fTargetArch) {
+ case UNW_TARGET_X86_64:
+ return get64(addr, err, arg);
+ break;
+ case UNW_TARGET_I386:
+ return get32(addr, err, arg);
+ break;
+ }
+ ABORT("Unknown target architecture.");
+ return 0;
+ }
+
+ bool findFunctionName(uint64_t addr, char *buf, size_t bufLen, unw_word_t *offset, void* arg);
+ bool findFunctionBounds(uint64_t addr, uint64_t& low, uint64_t& high, void* arg);
+ int setCachingPolicy(unw_caching_policy_t policy);
+
+ void setLoggingLevel(FILE *f, unw_log_level_t level);
+ void logInfo(const char *fmt, ...);
+ void logAPI(const char *fmt, ...);
+ void logVerbose(const char *fmt, ...);
+ void logDebug(const char *fmt, ...);
+ struct timeval *timestamp_start ();
+ void timestamp_stop (struct timeval *tstart, const char *fmt, ...);
+
+ void flushAllCaches() { fImages.removeAllImageProfiles(); }
+ void flushCacheByMachHeader(uint64_t mh) { fImages.removeOneImageProfiles(mh); }
+ unw_targettype_t getTargetArch() { return fTargetArch; }
+ unw_accessors_t* getAccessors () { return &fAccessors; }
+ RemoteRegisterMap* getRegisterMap() { return fRemoteRegisterMap; }
+ unw_addr_space_t wrap () { return (unw_addr_space_t) &fWrapper; }
+ bool remoteIsLittleEndian () { return fLittleEndian; }
+ unw_log_level_t getDebugLoggingLevel() { return fLogLevel; }
+ void addMemBlob (RemoteMemoryBlob *blob) { fImages.addMemBlob(blob); }
+ unw_caching_policy_t getCachingPolicy() { return fCachingPolicy; }
+
+private:
+ int readRaw(uint64_t addr, uint64_t extent, uint8_t *valp, void* arg)
+ {
+ uint8_t *t = this->getMemBlobMemory (addr, extent);
+ if (t) {
+ memcpy (valp, t, extent);
+ return 0;
+ }
+ return fAccessors.access_raw((unw_addr_space_t)this, addr, extent, valp, 0, arg);
+ }
+
+ struct unw_addr_space_remote fWrapper;
+ unw_accessors_t fAccessors;
+ unw_caching_policy_t fCachingPolicy;
+ unw_targettype_t fTargetArch;
+ unw_addr_space_t fAddrSpace;
+ RemoteImages fImages;
+ RemoteRegisterMap *fRemoteRegisterMap;
+ FILE *fLogging;
+ unw_log_level_t fLogLevel;
+ bool fLittleEndian;
+};
+
+// Find an image containing the given pc, returns false if absent and
+// we can't add it via the accessors.
+bool RemoteProcInfo::haveImageEntry (uint64_t pc, void *arg) {
+ if (fImages.remoteEntryForTextAddr (pc) == NULL) {
+ unw_word_t mh, text_start, text_end, eh_frame, eh_frame_len, compact_unwind, compact_unwind_len;
+ if (fAccessors.find_image_info (wrap(), pc, &mh, &text_start,
+ &text_end, &eh_frame, &eh_frame_len, &compact_unwind, &compact_unwind_len, arg) == UNW_ESUCCESS) {
+ fImages.addImage (mh, text_start, text_end, eh_frame, eh_frame_len, compact_unwind, compact_unwind_len);
+ if (fCachingPolicy != UNW_CACHE_NONE) {
+ if (compact_unwind_len != 0) {
+ logVerbose ("Creating RemoteMemoryBlob of compact unwind info image at mh 0x%llx, %lld bytes", mh, (uint64_t) compact_unwind_len);
+ uint8_t *buf = (uint8_t*) malloc (compact_unwind_len);
+ if (this->getBytes (compact_unwind, compact_unwind_len, buf, arg)) {
+ RemoteMemoryBlob *b = new RemoteMemoryBlob(buf, free, compact_unwind, compact_unwind_len, mh, NULL);
+ fImages.addMemBlob (b);
+ }
+ } else if (eh_frame_len != 0) {
+ logVerbose ("Creating RemoteMemoryBlob of eh_frame for image at mh 0x%llx, %lld bytes", mh, (uint64_t) compact_unwind_len);
+ uint8_t *buf = (uint8_t*) malloc (eh_frame_len);
+ if (this->getBytes (eh_frame, eh_frame_len, buf, arg)) {
+ RemoteMemoryBlob *b = new RemoteMemoryBlob(buf, free, eh_frame, eh_frame_len, mh, NULL);
+ fImages.addMemBlob (b);
+ }
+ }
+ }
+ } else {
+ return false; /// find_image_info failed
+ }
+ } else {
+ return true;
+ }
+ return true;
+}
+
+bool RemoteProcInfo::getImageAddresses (uint64_t pc, uint64_t &mh, uint64_t &text_start, uint64_t &text_end,
+ uint64_t &eh_frame_start, uint64_t &eh_frame_len, uint64_t &compact_unwind_start,
+ void *arg) {
+ // Make sure we have this RemoteImageEntry already - fetch it now if needed.
+ if (haveImageEntry (pc, arg) == false) {
+ return false;
+ }
+ RemoteImageEntry *r = fImages.remoteEntryForTextAddr (pc);
+ if (r) {
+ mh = r->mach_header;
+ text_start = r->text_start;
+ text_end = r->text_end;
+ eh_frame_start = r->eh_frame_start;
+ eh_frame_len = r->eh_frame_len;
+ compact_unwind_start = r->compact_unwind_info_start;
+ return true;
+ }
+ return false;
+}
+
+
+bool RemoteProcInfo::findFunctionName(uint64_t addr, char *buf, size_t bufLen, unw_word_t *offset, void* arg)
+{
+ if(fAccessors.get_proc_name(wrap(), addr, buf, bufLen, offset, arg) == UNW_ESUCCESS)
+ return true;
+ else
+ return false;
+}
+
+bool RemoteProcInfo::findFunctionBounds(uint64_t addr, uint64_t& low, uint64_t& high, void* arg)
+{
+ if (fAccessors.get_proc_bounds(wrap(), addr, &low, &high, arg) == UNW_ESUCCESS
+ && high != 0)
+ return true;
+ else
+ return false;
+}
+
+int RemoteProcInfo::setCachingPolicy(unw_caching_policy_t policy)
+{
+ if(policy == UNW_CACHE_NONE && fCachingPolicy != UNW_CACHE_NONE)
+ {
+ flushAllCaches();
+ }
+
+ if(!(policy == UNW_CACHE_NONE || policy == UNW_CACHE_GLOBAL || policy == UNW_CACHE_PER_THREAD))
+ return UNW_EINVAL;
+
+ fCachingPolicy = policy;
+
+ return UNW_ESUCCESS;
+}
+
+void RemoteProcInfo::setLoggingLevel(FILE *f, unw_log_level_t level)
+{
+ fLogLevel = level;
+ fLogging = f;
+}
+
+void RemoteProcInfo::logInfo(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_INFO) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+void RemoteProcInfo::logAPI(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_API) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+void RemoteProcInfo::logVerbose(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_VERBOSE) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+void RemoteProcInfo::logDebug(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_DEBUG) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+struct timeval *RemoteProcInfo::timestamp_start ()
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return NULL;
+ if (fLogLevel & UNW_LOG_LEVEL_TIMINGS) {
+ struct timeval *t = (struct timeval *) malloc (sizeof (struct timeval));
+ if (gettimeofday (t, NULL) != 0) {
+ free (t);
+ return NULL;
+ }
+ return t;
+ }
+ return NULL;
+}
+
+void RemoteProcInfo::timestamp_stop (struct timeval *tstart, const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE || tstart == NULL)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_TIMINGS) {
+ struct timeval tend;
+ if (gettimeofday (&tend, NULL) != 0) {
+ free (tstart);
+ return;
+ }
+ struct timeval result;
+ timersub (&tend, tstart, &result);
+ va_list ap;
+ va_start (ap, fmt);
+ vprintf (fmt, ap);
+ printf (" duration %0.5fs\n", (double) ((result.tv_sec * 1000000) + result.tv_usec) / 1000000.0);
+ va_end (ap);
+ free (tstart);
+ }
+}
+
+
+// Initialize the register context at the start of a remote unwind.
+
+void getRemoteContext (RemoteProcInfo* procinfo, Registers_x86_64& r, void *arg) {
+ unw_accessors_t* accessors = procinfo->getAccessors();
+ unw_addr_space_t addrSpace = procinfo->wrap();
+ RemoteRegisterMap* regmap = procinfo->getRegisterMap();
+ uint64_t rv;
+
+ // now that we have a selected process/thread, ask about the valid registers.
+ regmap->scan_caller_regs (addrSpace, arg);
+
+#define FILLREG(reg) {int caller_reg; regmap->unwind_regno_to_caller_regno ((reg), caller_reg); accessors->access_reg (addrSpace, caller_reg, &rv, 0, arg); r.setRegister ((reg), rv);}
+ FILLREG (UNW_X86_64_RAX);
+ FILLREG (UNW_X86_64_RDX);
+ FILLREG (UNW_X86_64_RCX);
+ FILLREG (UNW_X86_64_RBX);
+ FILLREG (UNW_X86_64_RSI);
+ FILLREG (UNW_X86_64_RDI);
+ FILLREG (UNW_X86_64_RBP);
+ FILLREG (UNW_X86_64_RSP);
+ FILLREG (UNW_X86_64_R8);
+ FILLREG (UNW_X86_64_R9);
+ FILLREG (UNW_X86_64_R10);
+ FILLREG (UNW_X86_64_R11);
+ FILLREG (UNW_X86_64_R12);
+ FILLREG (UNW_X86_64_R13);
+ FILLREG (UNW_X86_64_R14);
+ FILLREG (UNW_X86_64_R15);
+ FILLREG (UNW_REG_IP);
+#undef FILLREG
+}
+
+void getRemoteContext (RemoteProcInfo* procinfo, Registers_x86& r, void *arg) {
+ unw_accessors_t* accessors = procinfo->getAccessors();
+ unw_addr_space_t addrSpace = procinfo->wrap();
+ RemoteRegisterMap* regmap = procinfo->getRegisterMap();
+ uint64_t rv;
+
+ // now that we have a selected process/thread, ask about the valid registers.
+ regmap->scan_caller_regs (addrSpace, arg);
+
+#define FILLREG(reg) {int caller_reg; regmap->unwind_regno_to_caller_regno ((reg), caller_reg); accessors->access_reg (addrSpace, caller_reg, &rv, 0, arg); r.setRegister ((reg), rv);}
+ FILLREG (UNW_X86_EAX);
+ FILLREG (UNW_X86_ECX);
+ FILLREG (UNW_X86_EDX);
+ FILLREG (UNW_X86_EBX);
+ FILLREG (UNW_X86_EBP);
+ FILLREG (UNW_X86_ESP);
+ FILLREG (UNW_X86_ESI);
+ FILLREG (UNW_X86_EDI);
+ FILLREG (UNW_REG_IP);
+#undef FILLREG
+}
+
+
+void getRemoteContext (RemoteProcInfo* procinfo, Registers_ppc& r, void *arg) {
+ ABORT("ppc get remote context not implemented.");
+}
+
+}; // namespace lldb_private
+
+
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif // __REMOTE_PROC_INFO_HPP__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp
new file mode 100644
index 00000000000..19caae9a3f4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp
@@ -0,0 +1,405 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteRegisterMap.hpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Provide conversions between reigster names, the libunwind internal enums,
+// and the register numbers the program calling libunwind are using.
+
+#ifndef __REMOTE_REGISTER_MAP_HPP__
+#define __REMOTE_REGISTER_MAP_HPP__
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include "libunwind.h"
+#include <vector>
+
+namespace lldb_private
+{
+class RemoteRegisterMap {
+public:
+ RemoteRegisterMap (unw_accessors_t *accessors, unw_targettype_t target);
+ ~RemoteRegisterMap ();
+ void initialize_x86_64 ();
+ void initialize_i386 ();
+ bool name_to_caller_regno (const char *name, int& callerr);
+ bool name_to_unwind_regno (const char *name, int& unwindr);
+ bool unwind_regno_to_caller_regno (int unwindr, int& callerr);
+ bool nonvolatile_reg_p (int unwind_regno);
+ bool argument_regnum_p (int unwind_regno);
+ const char *ip_register_name();
+ const char *sp_register_name();
+ int caller_regno_for_ip ();
+ int caller_regno_for_sp ();
+ int unwind_regno_for_frame_pointer ();
+ int unwind_regno_for_stack_pointer ();
+ int wordsize () { return fWordSize; }
+ void scan_caller_regs (unw_addr_space_t as, void *arg);
+
+ bool unwind_regno_to_machine_regno (int unwindr, int& machiner);
+ bool machine_regno_to_unwind_regno (int machr, int& unwindr);
+ bool caller_regno_to_unwind_regno (int callerr, int& unwindr);
+ const char* unwind_regno_to_name (int unwindr);
+ int byte_size_for_regtype (unw_regtype_t type);
+
+private:
+
+ // A structure that collects everything we need to know about a
+ // given register in one place.
+ struct reg {
+ int unwind_regno; // What libunwind-remote uses internally
+ int caller_regno; // What the libunwind-remote driver program uses
+ int eh_frame_regno; // What the eh_frame section uses
+ int machine_regno; // What the actual bits/bytes are in instructions
+ char *name;
+ unw_regtype_t type;
+ reg () : unwind_regno(-1), machine_regno(-1), caller_regno(-1),
+ eh_frame_regno(-1), name(NULL), type(UNW_NOT_A_REG) { }
+ };
+
+ unw_accessors_t fAccessors;
+ unw_targettype_t fTarget;
+ std::vector<RemoteRegisterMap::reg> fRegMap;
+ int fWordSize;
+};
+
+void RemoteRegisterMap::initialize_x86_64 () {
+#define DEFREG(ureg, ehno, machno, regn) {RemoteRegisterMap::reg r; r.unwind_regno = ureg; r.name = regn; r.eh_frame_regno = ehno; r.machine_regno = machno; r.type = UNW_INTEGER_REG; fRegMap.push_back(r); }
+ DEFREG (UNW_X86_64_RAX, 0, 0, strdup ("rax"));
+ DEFREG (UNW_X86_64_RDX, 1, 2, strdup ("rdx"));
+ DEFREG (UNW_X86_64_RCX, 2, 1, strdup ("rcx"));
+ DEFREG (UNW_X86_64_RBX, 3, 3, strdup ("rbx"));
+ DEFREG (UNW_X86_64_RSI, 4, 6, strdup ("rsi"));
+ DEFREG (UNW_X86_64_RDI, 5, 7, strdup ("rdi"));
+ DEFREG (UNW_X86_64_RBP, 6, 5, strdup ("rbp"));
+ DEFREG (UNW_X86_64_RSP, 7, 4, strdup ("rsp"));
+ DEFREG (UNW_X86_64_R8, 8, 8, strdup ("r8"));
+ DEFREG (UNW_X86_64_R9, 9, 9, strdup ("r9"));
+ DEFREG (UNW_X86_64_R10, 10, 10, strdup ("r10"));
+ DEFREG (UNW_X86_64_R11, 11, 11, strdup ("r11"));
+ DEFREG (UNW_X86_64_R12, 12, 12, strdup ("r12"));
+ DEFREG (UNW_X86_64_R13, 13, 13, strdup ("r13"));
+ DEFREG (UNW_X86_64_R14, 14, 14, strdup ("r14"));
+ DEFREG (UNW_X86_64_R15, 15, 15, strdup ("r15"));
+#undef DEFREG
+ RemoteRegisterMap::reg r;
+ r.name = strdup ("rip");
+ r.type = UNW_INTEGER_REG;
+ r.eh_frame_regno = 16;
+ fRegMap.push_back(r);
+}
+
+void RemoteRegisterMap::initialize_i386 () {
+#define DEFREG(ureg, ehno, machno, regn) {RemoteRegisterMap::reg r; r.unwind_regno = ureg; r.name = regn; r.eh_frame_regno = ehno; r.machine_regno = machno; r.type = UNW_INTEGER_REG; fRegMap.push_back(r); }
+ DEFREG (UNW_X86_EAX, 0, 0, strdup ("eax"));
+ DEFREG (UNW_X86_ECX, 1, 1, strdup ("ecx"));
+ DEFREG (UNW_X86_EDX, 2, 2, strdup ("edx"));
+ DEFREG (UNW_X86_EBX, 3, 3, strdup ("ebx"));
+ // i386 EH frame info has the next two swapped,
+ // v. gcc/config/i386/darwin.h:DWARF2_FRAME_REG_OUT.
+ DEFREG (UNW_X86_EBP, 4, 5, strdup ("ebp"));
+ DEFREG (UNW_X86_ESP, 5, 4, strdup ("esp"));
+ DEFREG (UNW_X86_ESI, 6, 6, strdup ("esi"));
+ DEFREG (UNW_X86_EDI, 7, 7, strdup ("edi"));
+#undef DEFREG
+ RemoteRegisterMap::reg r;
+ r.name = strdup ("eip");
+ r.type = UNW_INTEGER_REG;
+ r.eh_frame_regno = 8;
+ fRegMap.push_back(r);
+}
+
+
+RemoteRegisterMap::RemoteRegisterMap (unw_accessors_t *accessors, unw_targettype_t target) {
+ fAccessors = *accessors;
+ fTarget = target;
+ switch (target) {
+ case UNW_TARGET_X86_64:
+ this->initialize_x86_64();
+ fWordSize = 8;
+ break;
+ case UNW_TARGET_I386:
+ this->initialize_i386();
+ fWordSize = 4;
+ break;
+ default:
+ ABORT("RemoteRegisterMap called with unknown target");
+ }
+}
+
+RemoteRegisterMap::~RemoteRegisterMap () {
+ std::vector<RemoteRegisterMap::reg>::iterator j;
+ for (j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ free (j->name);
+}
+
+bool RemoteRegisterMap::name_to_caller_regno (const char *name, int& callerr) {
+ if (name == NULL)
+ return false;
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (strcasecmp (j->name, name) == 0) {
+ callerr = j->caller_regno;
+ return true;
+ }
+ return false;
+}
+
+bool RemoteRegisterMap::unwind_regno_to_caller_regno (int unwindr, int& callerr) {
+ if (unwindr == UNW_REG_IP) {
+ callerr = this->caller_regno_for_ip ();
+ return true;
+ }
+ if (unwindr == UNW_REG_SP) {
+ callerr = this->caller_regno_for_sp ();
+ return true;
+ }
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->unwind_regno == unwindr && j->caller_regno != -1) {
+ callerr = j->caller_regno;
+ return true;
+ }
+ return false;
+}
+
+bool RemoteRegisterMap::nonvolatile_reg_p (int unwind_regno) {
+ if (fTarget == UNW_TARGET_X86_64) {
+ switch (unwind_regno) {
+ case UNW_X86_64_RBX:
+ case UNW_X86_64_RSP:
+ case UNW_X86_64_RBP: // not actually a nonvolatile but often treated as such by convention
+ case UNW_X86_64_R12:
+ case UNW_X86_64_R13:
+ case UNW_X86_64_R14:
+ case UNW_X86_64_R15:
+ case UNW_REG_IP:
+ case UNW_REG_SP:
+ return true;
+ break;
+ default:
+ return false;
+ }
+ }
+ if (fTarget == UNW_TARGET_I386) {
+ switch (unwind_regno) {
+ case UNW_X86_EBX:
+ case UNW_X86_EBP: // not actually a nonvolatile but often treated as such by convention
+ case UNW_X86_ESI:
+ case UNW_X86_EDI:
+ case UNW_X86_ESP:
+ case UNW_REG_IP:
+ case UNW_REG_SP:
+ return true;
+ break;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+
+bool RemoteRegisterMap::argument_regnum_p (int unwind_regno) {
+ if (fTarget == UNW_TARGET_X86_64) {
+ switch (unwind_regno) {
+ case UNW_X86_64_RDI: /* arg 1 */
+ case UNW_X86_64_RSI: /* arg 2 */
+ case UNW_X86_64_RDX: /* arg 3 */
+ case UNW_X86_64_RCX: /* arg 4 */
+ case UNW_X86_64_R8: /* arg 5 */
+ case UNW_X86_64_R9: /* arg 6 */
+ return true;
+ break;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+const char *RemoteRegisterMap::ip_register_name () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return "rip";
+ case UNW_TARGET_I386:
+ return "eip";
+ default:
+ ABORT("unsupported architecture");
+ }
+ return NULL;
+}
+
+const char *RemoteRegisterMap::sp_register_name () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return "rsp";
+ case UNW_TARGET_I386:
+ return "esp";
+ default:
+ ABORT("unsupported architecture");
+ }
+ return NULL;
+}
+
+int RemoteRegisterMap::caller_regno_for_ip () {
+ int callerr;
+ if (this->name_to_caller_regno (this->ip_register_name(), callerr))
+ return callerr;
+ return -1;
+}
+
+int RemoteRegisterMap::caller_regno_for_sp () {
+ int callerr;
+ if (this->name_to_caller_regno (this->sp_register_name(), callerr))
+ return callerr;
+ return -1;
+}
+
+int RemoteRegisterMap::unwind_regno_for_frame_pointer () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return UNW_X86_64_RBP;
+ case UNW_TARGET_I386:
+ return UNW_X86_EBP;
+ default:
+ ABORT("cannot be reached");
+ }
+ return -1;
+}
+
+int RemoteRegisterMap::unwind_regno_for_stack_pointer () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return UNW_X86_64_RSP;
+ case UNW_TARGET_I386:
+ return UNW_X86_ESP;
+ default:
+ ABORT("cannot be reached");
+ }
+ return -1;
+}
+
+// This call requires a "arg" which specifies a given process/thread to
+// complete unlike the rest of the RegisterMap functions. Ideally this
+// would be in the ctor but the register map is created when an
+// AddressSpace is created and we don't have a process/thread yet.
+
+void RemoteRegisterMap::scan_caller_regs (unw_addr_space_t as, void *arg) {
+ for (int i = 0; i < 256; i++) {
+ unw_regtype_t type;
+ char namebuf[16];
+ if (fAccessors.reg_info (as, i, &type, namebuf, sizeof (namebuf), arg) == UNW_ESUCCESS
+ && type != UNW_NOT_A_REG) {
+ std::vector<RemoteRegisterMap::reg>::iterator j;
+ for (j = fRegMap.begin(); j != fRegMap.end(); ++j) {
+ if (strcasecmp (j->name, namebuf) == 0) {
+ j->caller_regno = i;
+ // if we haven't picked up a reg type yet it will be UNW_NOT_A_REG via the ctor
+ if (j->type == UNW_NOT_A_REG)
+ j->type = type;
+ if (j->type != type) {
+ ABORT("Caller and libunwind disagree about type of register");
+ break;
+ }
+ }
+ }
+ // caller knows about a register we don't have a libunwind entry for
+ if (j == fRegMap.end()) {
+ RemoteRegisterMap::reg r;
+ r.name = strdup (namebuf);
+ r.caller_regno = i;
+ r.type = type;
+ fRegMap.push_back(r);
+ }
+ }
+ }
+}
+
+
+bool RemoteRegisterMap::name_to_unwind_regno (const char *name, int& unwindr) {
+ if (name == NULL)
+ return false;
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (strcasecmp (j->name, name) == 0) {
+ unwindr = j->unwind_regno;
+ return true;
+ }
+ return false;
+}
+
+bool RemoteRegisterMap::unwind_regno_to_machine_regno (int unwindr, int& machiner) {
+ if (unwindr == UNW_REG_IP)
+ unwindr = this->caller_regno_for_ip ();
+ if (unwindr == UNW_REG_SP)
+ unwindr = this->caller_regno_for_sp ();
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->unwind_regno == unwindr && j->machine_regno != -1) {
+ machiner = j->machine_regno;
+ return true;
+ }
+ return false;
+}
+bool RemoteRegisterMap::machine_regno_to_unwind_regno (int machr, int& unwindr) {
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->machine_regno == machr && j->unwind_regno != -1) {
+ unwindr = j->unwind_regno;
+ return true;
+ }
+ return false;
+}
+bool RemoteRegisterMap::caller_regno_to_unwind_regno (int callerr, int& unwindr) {
+ if (this->caller_regno_for_ip() == callerr) {
+ unwindr = UNW_REG_IP;
+ return true;
+ }
+ if (this->caller_regno_for_sp() == callerr) {
+ unwindr = UNW_REG_SP;
+ return true;
+ }
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->caller_regno == callerr && j->unwind_regno != -1) {
+ unwindr = j->unwind_regno;
+ return true;
+ }
+ return false;
+}
+
+const char* RemoteRegisterMap::unwind_regno_to_name (int unwindr) {
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->unwind_regno == unwindr && j->name != NULL) {
+ return j->name;
+ }
+ return NULL;
+}
+
+int RemoteRegisterMap::byte_size_for_regtype (unw_regtype_t type) {
+ switch (type) {
+ case UNW_TARGET_X86_64:
+ case UNW_TARGET_I386:
+ if (type == UNW_INTEGER_REG) return fWordSize;
+ if (type == UNW_FLOATING_POINT_REG) return 8;
+ if (type == UNW_VECTOR_REG) return 16;
+ default:
+ ABORT("cannot be reached");
+ }
+ return -1;
+}
+
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+#endif // __REMOTE_REGISTER_MAP_HPP__
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h
new file mode 100644
index 00000000000..b03551cd21c
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h
@@ -0,0 +1,85 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteUnwindProfile.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_PROFILE_H__
+#define __UNWIND_PROFILE_H__
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include <vector>
+
+// The architecture-independent profile of a function's prologue
+
+namespace lldb_private
+{
+
+class RemoteUnwindProfile {
+public:
+ RemoteUnwindProfile () : fRegistersSaved(32, 0), fRegSizes(10, 0) { }
+ struct CFALocation {
+ int regno;
+ int offset;
+ };
+ enum RegisterSavedWhere { kRegisterOffsetFromCFA, kRegisterIsCFA };
+ enum RegisterType { kGeneralPurposeRegister = 0, kFloatingPointRegister, kVectorRegister };
+ struct SavedReg {
+ int regno;
+ RegisterSavedWhere location;
+ int64_t value;
+ int adj; // Used in kRegisterInRegister e.g. when we recover the caller's rsp by
+ // taking the contents of rbp and subtracting 16.
+ RegisterType type;
+ };
+ // In the following maps the key is the address after which this change has effect.
+ //
+ // 0 push %rbp
+ // 1 mov %rsp, %rbp
+ // 2 sub $16, %rsp
+ //
+ // At saved_registers<2> we'll find the record stating that rsp is now stored in rbp.
+
+ std::map<uint64_t, CFALocation> cfa;
+ std::map<uint64_t, std::vector<SavedReg> > saved_registers;
+
+ struct CFALocation initial_cfa; // At entry to the function
+
+ std::vector<uint8_t> fRegistersSaved;
+ std::vector<uint8_t> fRegSizes;
+ SavedReg returnAddress;
+ uint64_t fStart, fEnd; // low and high pc values for this function.
+ // END is the addr of the first insn outside the function.
+ uint64_t fFirstInsnPastPrologue;
+};
+
+class RemoteProcInfo;
+
+bool AssemblyParse (RemoteProcInfo *procinfo, unw_accessors_t *as, unw_addr_space_t as, uint64_t start, uint64_t end, RemoteUnwindProfile &profile, void *arg);
+
+
+class FuncBounds {
+ public:
+ FuncBounds (uint64_t low, uint64_t high) : fStart(low), fEnd(high) { }
+ uint64_t fStart;
+ uint64_t fEnd;
+};
+
+inline bool operator<(const FuncBounds &ap1, const FuncBounds &ap2) {
+ if (ap1.fStart < ap2.fStart)
+ return true;
+ if (ap1.fStart == ap2.fStart && ap1.fEnd < ap2.fEnd)
+ return true;
+ return false;
+}
+
+
+};
+#endif
+
+
+#endif // __UNWIND_PROFILE_H__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c b/lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c
new file mode 100644
index 00000000000..584528353a4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c
@@ -0,0 +1,466 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- Unwind-sjlj.c -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ *
+ * Implements setjump-longjump based C++ exceptions
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <setjmp.h>
+
+#include "unwind.h"
+#include "InternalMacros.h"
+
+//
+// ARM uses setjump/longjump based C++ exceptions.
+// Other architectures use "zero cost" exceptions.
+//
+// With SJLJ based exceptions any function that has a catch clause or needs to do any clean up when
+// an exception propagates through it, needs to call _Unwind_SjLj_Register() at the start of the
+// function and _Unwind_SjLj_Unregister() at the end. The register function is called with the
+// address of a block of memory in the function's stack frame. The runtime keeps a linked list
+// (stack) of these blocks - one per thread. The calling function also sets the personality
+// and lsda fields of the block.
+//
+//
+#if __arm__
+
+struct _Unwind_FunctionContext
+{
+ // next function in stack of handlers
+ struct _Unwind_FunctionContext* prev;
+
+ // set by calling function before registering to be the landing pad
+ uintptr_t resumeLocation;
+
+ // set by personality handler to be parameters passed to landing pad function
+ uintptr_t resumeParameters[4];
+
+ // set by calling function before registering
+ __personality_routine personality; // arm offset=24
+ uintptr_t lsda; // arm offset=28
+
+ // variable length array, contains registers to restore
+ // 0 = r7, 1 = pc, 2 = sp
+ void* jbuf[];
+};
+
+
+#if FOR_DYLD
+ // implemented in dyld
+ extern struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack();
+ extern void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc);
+#else
+ static pthread_key_t sPerThreadTopOfFunctionStack = 0;
+ static pthread_once_t sOnceFlag = PTHREAD_ONCE_INIT;
+
+ static void __Unwind_SjLj_MakeTopOfFunctionStackKey()
+ {
+ pthread_key_create(&sPerThreadTopOfFunctionStack, NULL);
+ }
+
+ static struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack()
+ {
+ pthread_once(&sOnceFlag, __Unwind_SjLj_MakeTopOfFunctionStackKey);
+ return (struct _Unwind_FunctionContext*)pthread_getspecific(sPerThreadTopOfFunctionStack);
+ }
+
+ static void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc)
+ {
+ pthread_once(&sOnceFlag, __Unwind_SjLj_MakeTopOfFunctionStackKey);
+ pthread_setspecific(sPerThreadTopOfFunctionStack, fc);
+ }
+#endif
+
+
+//
+// Called at start of each function that catches exceptions
+//
+EXPORT void _Unwind_SjLj_Register(struct _Unwind_FunctionContext* fc)
+{
+ fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
+ __Unwind_SjLj_SetTopOfFunctionStack(fc);
+}
+
+
+//
+// Called at end of each function that catches exceptions
+//
+EXPORT void _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext* fc)
+{
+ __Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
+}
+
+
+static _Unwind_Reason_Code unwind_phase1(struct _Unwind_Exception* exception_object)
+{
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ DEBUG_PRINT_UNWINDING("unwind_phase1: initial function-context=%p\n", c);
+
+ // walk each frame looking for a place to stop
+ for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
+
+ // check for no more frames
+ if ( c == NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ DEBUG_PRINT_UNWINDING("unwind_phase1: function-context=%p\n", c);
+ // if there is a personality routine, ask it if it will want to stop at this frame
+ if ( c->personality != NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, c->personality);
+ _Unwind_Reason_Code personalityResult = (*c->personality)(1, _UA_SEARCH_PHASE,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c);
+ switch ( personalityResult ) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember function context
+ handlerNotFound = false;
+ exception_object->private_2 = (uintptr_t)c;
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
+
+ // walk each frame until we reach where search phase said to stop
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ while ( true ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2s(ex_ojb=%p): function-context=%p\n", exception_object, c);
+
+ // check for no more frames
+ if ( c == NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( c->personality != NULL ) {
+ _Unwind_Action action = _UA_CLEANUP_PHASE;
+ if ( (uintptr_t)c == exception_object->private_2 )
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
+ _Unwind_Reason_Code personalityResult = (*c->personality)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c);
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ // continue unwinding
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ if ( (uintptr_t)c == exception_object->private_2 ) {
+ // phase 1 said we would stop at this frame, but we did not...
+ ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT, will resume at landing pad %p\n", exception_object, c->jbuf[1]);
+ // personality routine says to transfer control to landing pad
+ // we may get control back if landing pad calls _Unwind_Resume()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ // unw_resume() only returns if there was an error
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // something went wrong
+ DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2_forced(struct _Unwind_Exception* exception_object,
+ _Unwind_Stop_Fn stop, void* stop_parameter)
+{
+ // walk each frame until we reach where search phase said to stop
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ while ( true ) {
+
+ // get next frame (skip over first which is _Unwind_RaiseException)
+ if ( c == NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // call stop function at each frame
+ _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
+ _Unwind_Reason_Code stopResult = (*stop)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c, stop_parameter);
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
+ if ( stopResult != _URC_NO_REASON ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( c->personality != NULL ) {
+ __personality_routine p = (__personality_routine)c->personality;
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
+ _Unwind_Reason_Code personalityResult = (*p)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c);
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
+ // destructors called, continue unwinding
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
+ // we may get control back if landing pad calls _Unwind_Resume()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ break;
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
+ exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // call stop function one last time and tell it we've reached the end of the stack
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
+ _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
+ (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)c, stop_parameter);
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+//
+// Called by __cxa_throw. Only returns if there is a fatal error
+//
+EXPORT _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object);
+
+ // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
+ if ( phase1 != _URC_NO_REASON )
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(exception_object);
+}
+
+
+//
+// When _Unwind_RaiseException() is in phase2, it hands control
+// to the personality function at each frame. The personality
+// may force a jump to a landing pad in that function, the landing
+// pad code may then call _Unwind_Resume() to continue with the
+// unwinding. Note: the call to _Unwind_Resume() is from compiler
+// geneated user code. All other _Unwind_* routines are called
+// by the C++ runtime __cxa_* routines.
+//
+// Re-throwing an exception is implemented by having the code call
+// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
+//
+EXPORT void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object);
+
+ if ( exception_object->private_1 != 0 )
+ unwind_phase2_forced(exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
+ else
+ unwind_phase2(exception_object);
+
+ // clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ ABORT("_Unwind_SjLj_Resume() can't return");
+}
+
+
+//
+// Called by __cxa_rethrow()
+//
+EXPORT _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1);
+ // if this is non-forced and a stopping place was found, then this is a re-throw
+ // call _Unwind_RaiseException() as if this was a new exception
+ if ( exception_object->private_1 == 0 )
+ _Unwind_SjLj_RaiseException(exception_object);
+
+ // call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
+ _Unwind_SjLj_Resume(exception_object);
+ ABORT("__Unwind_SjLj_Resume_or_Rethrow() called _Unwind_SjLj_Resume() which unexpectedly returned");
+}
+
+
+//
+// Called by personality handler during phase 2 to get LSDA for current frame
+//
+EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
+{
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%0lX\n", context, ufc->lsda);
+ return ufc->lsda;
+}
+
+
+//
+// Called by personality handler during phase 2 to get register values
+//
+EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
+{
+ DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d)\n", context, index);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ return ufc->resumeParameters[index];
+}
+
+
+
+//
+// Called by personality handler during phase 2 to alter register values
+//
+EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n", context, index, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ ufc->resumeParameters[index] = new_value;
+}
+
+
+//
+// Called by personality handler during phase 2 to get instruction pointer
+//
+EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
+{
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, ufc->resumeLocation+1);
+ return ufc->resumeLocation+1;
+}
+
+//
+// Called by personality handler during phase 2 to get instruction pointer
+// ipBefore is a boolean that says if IP is already adjusted to be the call
+// site address. Normally IP is the return address.
+//
+EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
+{
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ *ipBefore = 0;
+ DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", context, ipBefore, ufc->resumeLocation+1);
+ return ufc->resumeLocation+1;
+}
+
+
+//
+// Called by personality handler during phase 2 to alter instruction pointer
+//
+EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n", context, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ ufc->resumeLocation = new_value-1;
+}
+
+//
+// Called by personality handler during phase 2 to find the start of the function
+//
+EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
+{
+ // Not supported or needed for sjlj based unwinding
+ DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p)\n", context);
+ return 0;
+}
+
+//
+// Called by personality handler during phase 2 if a foreign exception is caught
+//
+EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
+ if ( exception_object->exception_cleanup != NULL )
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
+}
+
+
+//
+// Called by personality handler during phase 2 to get base address for data relative encodings
+//
+EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
+{
+ // Not supported or needed for sjlj based unwinding
+ DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+//
+// Called by personality handler during phase 2 to get base address for text relative encodings
+//
+EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
+{
+ // Not supported or needed for sjlj based unwinding
+ DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+
+//
+// Called by personality handler to get Call Frame Area for current frame
+//
+EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
+{
+ DEBUG_PRINT_API("_Unwind_GetCFA(context=%p)\n", context);
+ if ( context != NULL ) {
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ // setjmp/longjmp based exceptions don't have a true CFA
+ // the SP in the jmpbuf is the closest approximation
+ return (uintptr_t)ufc->jbuf[2];
+ }
+ return 0;
+}
+
+
+
+
+
+#endif // __arm__
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__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c
new file mode 100644
index 00000000000..7103c719ba2
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c
@@ -0,0 +1,282 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- UnwindLevel1-gcc-ext.c ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ * Implements gcc extensions to the C++ ABI Exception Handling Level 1 as documented at:
+ * <http://www.codesourcery.com/cxx-abi/abi-eh.html>
+ * using libunwind
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "libunwind_priv.h"
+#include "InternalMacros.h"
+
+
+#if __ppc__ || __i386__ || __x86_64__
+
+//
+// Called by __cxa_rethrow()
+//
+EXPORT _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1);
+ // if this is non-forced and a stopping place was found, then this is a re-throw
+ // call _Unwind_RaiseException() as if this was a new exception
+ if ( exception_object->private_1 == 0 )
+ _Unwind_RaiseException(exception_object);
+
+ // call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
+ _Unwind_Resume(exception_object);
+ ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException() which unexpectedly returned");
+}
+
+
+
+//
+// Called by personality handler during phase 2 to get base address for data relative encodings
+//
+EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
+{
+ DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+//
+// Called by personality handler during phase 2 to get base address for text relative encodings
+//
+EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
+{
+ DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+
+//
+// Scans unwind information to find the function that contains the
+// specified code address "pc".
+//
+EXPORT void* _Unwind_FindEnclosingFunction(void* pc)
+{
+ DEBUG_PRINT_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc);
+ ABORT("_Unwind_FindEnclosingFunction() not implemented");
+}
+
+
+//
+// Walk every frame and call trace function at each one. If trace function
+// returns anything other than _URC_NO_REASON, then walk is terminated.
+//
+EXPORT _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn callback, void* ref)
+{
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+
+ DEBUG_PRINT_API("_Unwind_Backtrace(callback=%p)\n", callback);
+
+ // walk each frame
+ while ( true ) {
+
+ // ask libuwind to get next frame (skip over first frame which is _Unwind_Backtrace())
+ if ( unw_step(&cursor) <= 0 ) {
+ DEBUG_PRINT_UNWINDING(" _backtrace: ended because cursor reached bottom of stack, returning %d\n", _URC_END_OF_STACK);
+ return _URC_END_OF_STACK;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_proc_info_t frameInfo;
+ unw_word_t offset;
+ unw_get_proc_name(&cursor, functionName, 512, &offset);
+ unw_get_proc_info(&cursor, &frameInfo);
+ DEBUG_PRINT_UNWINDING(" _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n",
+ frameInfo.start_ip, functionName, frameInfo.lsda, &cursor);
+ }
+
+ // call trace function with this frame
+ _Unwind_Reason_Code result = (*callback)((struct _Unwind_Context*)(&cursor), ref);
+ if ( result != _URC_NO_REASON ) {
+ DEBUG_PRINT_UNWINDING(" _backtrace: ended because callback returned %d\n", result);
+ return result;
+ }
+ }
+}
+
+
+//
+// Find dwarf unwind info for an address 'pc' in some function.
+//
+EXPORT const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases* bases)
+{
+ // This is slow, but works.
+ // We create an unwind cursor then alter the IP to be pc
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_proc_info_t info;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+ unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc);
+ unw_get_proc_info(&cursor, &info);
+ bases->tbase = info.extra;
+ bases->dbase = 0; // dbase not used on Mac OS X
+ bases->func = info.start_ip;
+ DEBUG_PRINT_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, (void*)(long)info.unwind_info);
+ return (void*)(long)info.unwind_info;
+}
+
+
+
+EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_word_t result;
+ unw_get_reg(cursor, UNW_REG_SP, &result);
+ DEBUG_PRINT_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context, (uint64_t)result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to get instruction pointer.
+// ipBefore is a boolean that says if IP is already adjusted to be the call
+// site address. Normally IP is the return address.
+//
+EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
+{
+ DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p)\n", context);
+ *ipBefore = 0;
+ return _Unwind_GetIP(context);
+}
+
+
+//
+// Called by programs with dynamic code generators that want
+// to register a dynamically generated FDE.
+// This function has existed on Mac OS X since 10.4, but
+// never worked before.
+//
+EXPORT void __register_frame(const void* fde)
+{
+ DEBUG_PRINT_API("__register_frame(%p)\n", fde);
+ _unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
+}
+
+
+//
+// Called by programs with dynamic code generators that want
+// to unregister a dynamically generated FDE.
+// This function has existed on Mac OS X since 10.4, but
+// never worked before.
+//
+EXPORT void __deregister_frame(const void* fde)
+{
+ DEBUG_PRINT_API("__deregister_frame(%p)\n", fde);
+ _unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
+}
+
+
+
+//
+// The following register/deregister functions are gcc extensions.
+// They have existed on Mac OS X, but have never worked because Mac OS X
+// before 10.6 used keymgr to track known FDEs, but these functions
+// never got updated to use keymgr.
+// For now, we implement these as do-nothing functions to keep any existing
+// applications working. We also add the not in 10.6 symbol so that nwe
+// application won't be able to use them.
+//
+
+EXPORT void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db)
+{
+ DEBUG_PRINT_API("__register_frame_info_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void __register_frame_info(const void* fde, void* ob)
+{
+ DEBUG_PRINT_API("__register_frame_info(%p, %p)\n", fde, ob);
+ // do nothing, this function never worked in Mac OS X
+}
+
+
+EXPORT void __register_frame_info_table_bases(const void* fde, void* ob, void* tb, void* db)
+{
+ DEBUG_PRINT_API("__register_frame_info_table_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void __register_frame_info_table(const void* fde, void* ob)
+{
+ DEBUG_PRINT_API("__register_frame_info_table(%p, %p)\n", fde, ob);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void __register_frame_table(const void* fde)
+{
+ DEBUG_PRINT_API("__register_frame_table(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void* __deregister_frame_info(const void* fde)
+{
+ DEBUG_PRINT_API("__deregister_frame_info(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+ return NULL;
+}
+
+EXPORT void* __deregister_frame_info_bases(const void* fde)
+{
+ DEBUG_PRINT_API("__deregister_frame_info_bases(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+ return NULL;
+}
+
+
+
+
+//
+// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
+//
+NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
+NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
+NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
+NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
+
+NOT_HERE_BEFORE_10_6(__register_frame)
+NOT_HERE_BEFORE_10_6(__deregister_frame)
+
+
+//
+// symbols in libSystem.dylib for compatibility, but we don't want any new code using them
+//
+NEVER_HERE(__register_frame_info_bases)
+NEVER_HERE(__register_frame_info)
+NEVER_HERE(__register_frame_info_table_bases)
+NEVER_HERE(__register_frame_info_table)
+NEVER_HERE(__register_frame_table)
+NEVER_HERE(__deregister_frame_info)
+NEVER_HERE(__deregister_frame_info_bases)
+
+
+#endif // __ppc__ || __i386__ || __x86_64__
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c
new file mode 100644
index 00000000000..3aa2b6f552c
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c
@@ -0,0 +1,443 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- UnwindLevel1.c ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ *
+ * Implements C++ ABI Exception Handling Level 1 as documented at:
+ * <http://www.codesourcery.com/cxx-abi/abi-eh.html>
+ * using libunwind
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "InternalMacros.h"
+
+#if __ppc__ || __i386__ || __x86_64__
+
+static _Unwind_Reason_Code unwind_phase1(unw_context_t* uc, struct _Unwind_Exception* exception_object)
+{
+ unw_cursor_t cursor1;
+ unw_init_local(&cursor1, uc);
+
+ // walk each frame looking for a place to stop
+ for (bool handlerNotFound = true; handlerNotFound; ) {
+
+ // ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
+ int stepResult = unw_step(&cursor1);
+ if ( stepResult == 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+ else if ( stepResult < 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // see if frame has code to run (has personality routine)
+ unw_proc_info_t frameInfo;
+ unw_word_t sp;
+ if ( unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_word_t offset;
+ if ( (unw_get_proc_name(&cursor1, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
+ strcpy(functionName, ".anonymous.");
+ unw_word_t pc;
+ unw_get_reg(&cursor1, UNW_REG_IP, &pc);
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
+ exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
+ }
+
+ // if there is a personality routine, ask it if it will want to stop at this frame
+ if ( frameInfo.handler != 0 ) {
+ __personality_routine p = (__personality_routine)(long)(frameInfo.handler);
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, p);
+ _Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor1));
+ switch ( personalityResult ) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember stack pointer at the frame
+ handlerNotFound = false;
+ unw_get_reg(&cursor1, UNW_REG_SP, &sp);
+ exception_object->private_2 = sp;
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2(unw_context_t* uc, struct _Unwind_Exception* exception_object)
+{
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
+
+ // walk each frame until we reach where search phase said to stop
+ while ( true ) {
+
+ // ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
+ int stepResult = unw_step(&cursor2);
+ if ( stepResult == 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+ else if ( stepResult < 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // get info about this frame
+ unw_word_t sp;
+ unw_proc_info_t frameInfo;
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_word_t offset;
+ if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
+ strcpy(functionName, ".anonymous.");
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, lsda=0x%llX, personality=0x%llX\n",
+ exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler);
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( frameInfo.handler != 0 ) {
+ __personality_routine p = (__personality_routine)(long)(frameInfo.handler);
+ _Unwind_Action action = _UA_CLEANUP_PHASE;
+ if ( sp == exception_object->private_2 )
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
+ _Unwind_Reason_Code personalityResult = (*p)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor2));
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ // continue unwinding
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ if ( sp == exception_object->private_2 ) {
+ // phase 1 said we would stop at this frame, but we did not...
+ ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object);
+ // personality routine says to transfer control to landing pad
+ // we may get control back if landing pad calls _Unwind_Resume()
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ unw_word_t pc;
+ unw_word_t sp;
+ unw_get_reg(&cursor2, UNW_REG_IP, &pc);
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp);
+ }
+ unw_resume(&cursor2);
+ // unw_resume() only returns if there was an error
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // something went wrong
+ DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t* uc, struct _Unwind_Exception* exception_object,
+ _Unwind_Stop_Fn stop, void* stop_parameter)
+{
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ // walk each frame until we reach where search phase said to stop
+ while ( unw_step(&cursor2) > 0 ) {
+
+ // get info about this frame
+ unw_proc_info_t frameInfo;
+ if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step failed => _URC_END_OF_STACK\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_word_t offset;
+ if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
+ strcpy(functionName, ".anonymous.");
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
+ exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
+ }
+
+ // call stop function at each frame
+ _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
+ _Unwind_Reason_Code stopResult = (*stop)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor2), stop_parameter);
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
+ if ( stopResult != _URC_NO_REASON ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( frameInfo.handler != 0 ) {
+ __personality_routine p = (__personality_routine)(long)(frameInfo.handler);
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
+ _Unwind_Reason_Code personalityResult = (*p)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor2));
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
+ // destructors called, continue unwinding
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
+ // we may get control back if landing pad calls _Unwind_Resume()
+ unw_resume(&cursor2);
+ break;
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
+ exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // call stop function one last time and tell it we've reached the end of the stack
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
+ _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
+ (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)(&cursor2), stop_parameter);
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+//
+// Called by __cxa_throw. Only returns if there is a fatal error
+//
+EXPORT _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_RaiseException(ex_obj=%p)\n", exception_object);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object);
+ if ( phase1 != _URC_NO_REASON )
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(&uc, exception_object);
+}
+
+
+//
+// When _Unwind_RaiseException() is in phase2, it hands control
+// to the personality function at each frame. The personality
+// may force a jump to a landing pad in that function, the landing
+// pad code may then call _Unwind_Resume() to continue with the
+// unwinding. Note: the call to _Unwind_Resume() is from compiler
+// geneated user code. All other _Unwind_* routines are called
+// by the C++ runtime __cxa_* routines.
+//
+// Re-throwing an exception is implemented by having the code call
+// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
+//
+EXPORT void _Unwind_Resume(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_Resume(ex_obj=%p)\n", exception_object);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ if ( exception_object->private_1 != 0 )
+ unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
+ else
+ unwind_phase2(&uc, exception_object);
+
+ // clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ ABORT("_Unwind_Resume() can't return");
+}
+
+
+
+//
+// Not used by C++.
+// Unwinds stack, calling "stop" function at each frame
+// Could be used to implement longjmp().
+//
+EXPORT _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter)
+{
+ DEBUG_PRINT_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", exception_object, stop);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // mark that this is a forced unwind, so _Unwind_Resume() can do the right thing
+ exception_object->private_1 = (uintptr_t)stop;
+ exception_object->private_2 = (uintptr_t)stop_parameter;
+
+ // doit
+ return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
+}
+
+
+//
+// Called by personality handler during phase 2 to get LSDA for current frame
+//
+EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
+ result = frameInfo.lsda;
+ DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lX\n", context, result);
+ if ( result != 0 ) {
+ if ( *((uint8_t*)result) != 0xFF )
+ DEBUG_MESSAGE("lsda at 0x%lX does not start with 0xFF\n", result);
+ }
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to get register values
+//
+EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_word_t result;
+ unw_get_reg(cursor, index, &result);
+ DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%llX\n", context, index, (uint64_t)result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to alter register values
+//
+EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0llX)\n", context, index, (uint64_t)new_value);
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_set_reg(cursor, index, new_value);
+}
+
+
+//
+// Called by personality handler during phase 2 to get instruction pointer
+//
+EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_word_t result;
+ unw_get_reg(cursor, UNW_REG_IP, &result);
+ DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%llX\n", context, (uint64_t)result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to alter instruction pointer
+//
+EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n", context, (uint64_t)new_value);
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_set_reg(cursor, UNW_REG_IP, new_value);
+}
+
+
+//
+// Called by personality handler during phase 2 to find the start of the function
+//
+EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
+ result = frameInfo.start_ip;
+ DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", context, result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 if a foreign exception is caught
+//
+EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
+ if ( exception_object->exception_cleanup != NULL )
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
+}
+
+
+
+
+//
+// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
+//
+NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
+NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
+NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
+NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume)
+NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
+
+#endif // __ppc__ || __i386__ || __x86_64__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h b/lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h
new file mode 100644
index 00000000000..83414332c5e
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h
@@ -0,0 +1,245 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- dwarf2.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/* These constants were taken from version 3 of the DWARF standard,
+ which is Copyright (c) 2005 Free Standards Group, and
+ Copyright (c) 1992, 1993 UNIX International, Inc.
+*/
+
+
+#ifndef __DWARF2__
+#define __DWARF2__
+
+namespace lldb_private {
+
+// dwarf unwind instructions
+enum {
+ DW_CFA_nop = 0x0,
+ DW_CFA_set_loc = 0x1,
+ DW_CFA_advance_loc1 = 0x2,
+ DW_CFA_advance_loc2 = 0x3,
+ DW_CFA_advance_loc4 = 0x4,
+ DW_CFA_offset_extended = 0x5,
+ DW_CFA_restore_extended = 0x6,
+ DW_CFA_undefined = 0x7,
+ DW_CFA_same_value = 0x8,
+ DW_CFA_register = 0x9,
+ DW_CFA_remember_state = 0xA,
+ DW_CFA_restore_state = 0xB,
+ DW_CFA_def_cfa = 0xC,
+ DW_CFA_def_cfa_register = 0xD,
+ DW_CFA_def_cfa_offset = 0xE,
+ DW_CFA_def_cfa_expression = 0xF,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
+ DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
+ DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
+
+ // GNU extensions
+ DW_CFA_GNU_window_save = 0x2D,
+ DW_CFA_GNU_args_size = 0x2E,
+ DW_CFA_GNU_negative_offset_extended = 0x2F
+};
+
+
+// FSF exception handling Pointer-Encoding constants
+// Used in CFI augmentation by gcc compiler
+enum {
+ DW_EH_PE_ptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_signed = 0x08,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+ DW_EH_PE_indirect = 0x80,
+ DW_EH_PE_omit = 0xFF
+};
+
+
+// DWARF expressions
+enum {
+ DW_OP_addr = 0x03, // constant address (size target specific)
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08, // 1-byte constant
+ DW_OP_const1s = 0x09, // 1-byte constant
+ DW_OP_const2u = 0x0A, // 2-byte constant
+ DW_OP_const2s = 0x0B, // 2-byte constant
+ DW_OP_const4u = 0x0C, // 4-byte constant
+ DW_OP_const4s = 0x0D, // 4-byte constant
+ DW_OP_const8u = 0x0E, // 8-byte constant
+ DW_OP_const8s = 0x0F, // 8-byte constant
+ DW_OP_constu = 0x10, // ULEB128 constant
+ DW_OP_consts = 0x11, // SLEB128 constant
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15, // 1-byte stack index
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1A,
+ DW_OP_div = 0x1B,
+ DW_OP_minus = 0x1C,
+ DW_OP_mod = 0x1D,
+ DW_OP_mul = 0x1E,
+ DW_OP_neg = 0x1F,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23, // ULEB128 addend
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_skip = 0x2F, // signed 2-byte constant
+ DW_OP_bra = 0x28, // signed 2-byte constant
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2A,
+ DW_OP_gt = 0x2B,
+ DW_OP_le = 0x2C,
+ DW_OP_lt = 0x2D,
+ DW_OP_ne = 0x2E,
+ DW_OP_lit0 = 0x30, // Literal 0
+ DW_OP_lit1 = 0x31, // Literal 1
+ DW_OP_lit2 = 0x32, // Literal 2
+ DW_OP_lit3 = 0x33, // Literal 3
+ DW_OP_lit4 = 0x34, // Literal 4
+ DW_OP_lit5 = 0x35, // Literal 5
+ DW_OP_lit6 = 0x36, // Literal 6
+ DW_OP_lit7 = 0x37, // Literal 7
+ DW_OP_lit8 = 0x38, // Literal 8
+ DW_OP_lit9 = 0x39, // Literal 9
+ DW_OP_lit10 = 0x3A, // Literal 10
+ DW_OP_lit11 = 0x3B, // Literal 11
+ DW_OP_lit12 = 0x3C, // Literal 12
+ DW_OP_lit13 = 0x3D, // Literal 13
+ DW_OP_lit14 = 0x3E, // Literal 14
+ DW_OP_lit15 = 0x3F, // Literal 15
+ DW_OP_lit16 = 0x40, // Literal 16
+ DW_OP_lit17 = 0x41, // Literal 17
+ DW_OP_lit18 = 0x42, // Literal 18
+ DW_OP_lit19 = 0x43, // Literal 19
+ DW_OP_lit20 = 0x44, // Literal 20
+ DW_OP_lit21 = 0x45, // Literal 21
+ DW_OP_lit22 = 0x46, // Literal 22
+ DW_OP_lit23 = 0x47, // Literal 23
+ DW_OP_lit24 = 0x48, // Literal 24
+ DW_OP_lit25 = 0x49, // Literal 25
+ DW_OP_lit26 = 0x4A, // Literal 26
+ DW_OP_lit27 = 0x4B, // Literal 27
+ DW_OP_lit28 = 0x4C, // Literal 28
+ DW_OP_lit29 = 0x4D, // Literal 29
+ DW_OP_lit30 = 0x4E, // Literal 30
+ DW_OP_lit31 = 0x4F, // Literal 31
+ DW_OP_reg0 = 0x50, // Contents of reg0
+ DW_OP_reg1 = 0x51, // Contents of reg1
+ DW_OP_reg2 = 0x52, // Contents of reg2
+ DW_OP_reg3 = 0x53, // Contents of reg3
+ DW_OP_reg4 = 0x54, // Contents of reg4
+ DW_OP_reg5 = 0x55, // Contents of reg5
+ DW_OP_reg6 = 0x56, // Contents of reg6
+ DW_OP_reg7 = 0x57, // Contents of reg7
+ DW_OP_reg8 = 0x58, // Contents of reg8
+ DW_OP_reg9 = 0x59, // Contents of reg9
+ DW_OP_reg10 = 0x5A, // Contents of reg10
+ DW_OP_reg11 = 0x5B, // Contents of reg11
+ DW_OP_reg12 = 0x5C, // Contents of reg12
+ DW_OP_reg13 = 0x5D, // Contents of reg13
+ DW_OP_reg14 = 0x5E, // Contents of reg14
+ DW_OP_reg15 = 0x5F, // Contents of reg15
+ DW_OP_reg16 = 0x60, // Contents of reg16
+ DW_OP_reg17 = 0x61, // Contents of reg17
+ DW_OP_reg18 = 0x62, // Contents of reg18
+ DW_OP_reg19 = 0x63, // Contents of reg19
+ DW_OP_reg20 = 0x64, // Contents of reg20
+ DW_OP_reg21 = 0x65, // Contents of reg21
+ DW_OP_reg22 = 0x66, // Contents of reg22
+ DW_OP_reg23 = 0x67, // Contents of reg23
+ DW_OP_reg24 = 0x68, // Contents of reg24
+ DW_OP_reg25 = 0x69, // Contents of reg25
+ DW_OP_reg26 = 0x6A, // Contents of reg26
+ DW_OP_reg27 = 0x6B, // Contents of reg27
+ DW_OP_reg28 = 0x6C, // Contents of reg28
+ DW_OP_reg29 = 0x6D, // Contents of reg29
+ DW_OP_reg30 = 0x6E, // Contents of reg30
+ DW_OP_reg31 = 0x6F, // Contents of reg31
+ DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
+ DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
+ DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
+ DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
+ DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
+ DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
+ DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
+ DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
+ DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
+ DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
+ DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
+ DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
+ DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
+ DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
+ DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
+ DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
+ DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
+ DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
+ DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
+ DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
+ DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
+ DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
+ DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
+ DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
+ DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
+ DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
+ DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
+ DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
+ DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
+ DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
+ DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
+ DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
+ DW_OP_regx = 0x90, // ULEB128 register
+ DW_OP_fbreg = 0x91, // SLEB128 offset
+ DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93, // ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
+ DW_OP_nop = 0x96,
+ DW_OP_push_object_addres = 0x97,
+ DW_OP_call2 = 0x98, // 2-byte offset of DIE
+ DW_OP_call4 = 0x99, // 4-byte offset of DIE
+ DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
+ DW_OP_lo_user = 0xE0,
+ DW_OP_APPLE_uninit = 0xF0,
+ DW_OP_hi_user = 0xFF
+};
+
+
+}; // namespace lldb_private
+
+
+#endif
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h b/lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h
new file mode 100644
index 00000000000..fe25780c538
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h
@@ -0,0 +1,35 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- libunwind_priv.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND_PRIV__
+#define __LIBUNWIND_PRIV__
+
+namespace lldb_private {
+#include "libunwind.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // SPI
+ extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
+
+ // IPI
+ extern void _unw_add_dynamic_fde(unw_word_t fde);
+ extern void _unw_remove_dynamic_fde(unw_word_t fde);
+
+#ifdef __cplusplus
+}
+#endif
+
+}; // namespace lldb_private
+
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx b/lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx
new file mode 100644
index 00000000000..e7e66a452f0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx
@@ -0,0 +1,421 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- libuwind.cxx --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if __ppc__ || __i386__ || __x86_64__
+
+#include <mach/mach_types.h>
+#include <mach/machine.h>
+#include <new>
+
+#include "libunwind.h"
+#include "libunwind_priv.h"
+
+#include "UnwindCursor.hpp"
+#include "AddressSpace.hpp"
+
+#include "RemoteProcInfo.hpp"
+
+namespace lldb_private {
+
+// setup debug logging hooks
+INITIALIZE_DEBUG_PRINT_API
+INITIALIZE_DEBUG_PRINT_UNWINDING
+
+// internal object to represent this processes address space
+static LocalAddressSpace sThisAddressSpace;
+
+#pragma mark Local API
+
+///
+/// record the registers and stack position of the caller
+///
+extern int unw_getcontext(unw_context_t*);
+// note: unw_getcontext() implemented in assembly
+
+///
+/// create a cursor of a thread in this process given 'context' recorded by unw_getcontext()
+///
+EXPORT int unw_init_local(unw_cursor_t* cursor, unw_context_t* context)
+{
+ DEBUG_PRINT_API("unw_init_local(cursor=%p, context=%p)\n", cursor, context);
+ // use "placement new" to allocate UnwindCursor in the cursor buffer
+#if __i386__
+ new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86>(context, sThisAddressSpace);
+#elif __x86_64__
+ new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86_64>(context, sThisAddressSpace);
+#elif __ppc__
+ new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_ppc>(context, sThisAddressSpace);
+#endif
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ co->setInfoBasedOnIPRegister(NULL);
+
+ return UNW_ESUCCESS;
+}
+
+///
+/// move cursor to next frame
+///
+EXPORT int unw_step(unw_cursor_t* cursor)
+{
+ DEBUG_PRINT_API("unw_step(cursor=%p)\n", cursor);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->step();
+}
+
+///
+/// get value of specified register at cursor position in stack frame
+///
+EXPORT int unw_get_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t* value)
+{
+ DEBUG_PRINT_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if (co->validReg(regNum) == 0)
+ return UNW_EBADREG;
+ return co->getReg(regNum, value);
+}
+
+///
+/// get value of specified float register at cursor position in stack frame
+///
+EXPORT int unw_get_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t* value)
+{
+ DEBUG_PRINT_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if ( co->validFloatReg(regNum) ) {
+ return co->getFloatReg(regNum, value);
+ }
+ return UNW_EBADREG;
+}
+
+///
+/// set value of specified register at cursor position in stack frame
+///
+EXPORT int unw_set_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t value)
+{
+ DEBUG_PRINT_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if ( co->validReg(regNum) ) {
+ co->setReg(regNum, value);
+ // specical case altering IP to re-find info (being called by personality function)
+ if ( regNum == UNW_REG_IP ) {
+ unw_proc_info_t info;
+ co->getInfo(&info);
+ uint64_t orgArgSize = info.gp;
+ uint64_t orgFuncStart = info.start_ip;
+ co->setInfoBasedOnIPRegister(false);
+ // and adjust REG_SP if there was a DW_CFA_GNU_args_size
+ if ( (orgFuncStart == info.start_ip) && (orgArgSize != 0) )
+ co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize);
+ }
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+///
+/// set value of specified float register at cursor position in stack frame
+///
+EXPORT int unw_set_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t value)
+{
+ DEBUG_PRINT_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if ( co->validFloatReg(regNum) ) {
+ return co->setFloatReg(regNum, value);
+ }
+ return UNW_EBADREG;
+}
+
+///
+/// resume execution at cursor position (aka longjump)
+///
+EXPORT int unw_resume(unw_cursor_t* cursor)
+{
+ DEBUG_PRINT_API("unw_resume(cursor=%p)\n", cursor);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ co->jumpto();
+ return UNW_EUNSPEC;
+}
+
+///
+/// returns the name of a register
+///
+EXPORT const char* unw_regname(unw_cursor_t* cursor, unw_regnum_t regNum)
+{
+ DEBUG_PRINT_API("unw_regname(cursor=%p, regNum=%d)\n", cursor, regNum);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->getRegisterName(regNum);
+}
+
+///
+/// get unwind info at cursor position in stack frame
+///
+EXPORT int unw_get_proc_info(unw_cursor_t* cursor, unw_proc_info_t* info)
+{
+ DEBUG_PRINT_API("unw_get_proc_info(cursor=%p, &info=%p)\n", cursor, info);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ co->getInfo(info);
+ if ( info->end_ip == 0 )
+ return UNW_ENOINFO;
+ else
+ return UNW_ESUCCESS;
+}
+
+///
+/// checks if a register is a floating-point register
+///
+EXPORT int unw_is_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum)
+{
+ DEBUG_PRINT_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", cursor, regNum);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->validFloatReg(regNum);
+}
+
+///
+/// checks if current frame is signal trampoline
+///
+EXPORT int unw_is_signal_frame(unw_cursor_t* cursor)
+{
+ DEBUG_PRINT_API("unw_is_signal_frame(cursor=%p)\n", cursor);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->isSignalFrame();
+}
+
+///
+/// get name of function at cursor position in stack frame
+///
+EXPORT int unw_get_proc_name(unw_cursor_t* cursor, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ DEBUG_PRINT_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%ld)\n", cursor, buf, bufLen);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ if ( co->getFunctionName(buf, bufLen, offset) )
+ return UNW_ESUCCESS;
+ else
+ return UNW_EUNSPEC;
+}
+
+#pragma mark Remote API
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+EXPORT int unw_init_remote(unw_cursor_t *cursor, unw_addr_space_t as, void *arg)
+{
+ DEBUG_PRINT_API("init_remote(c=%p, as=%p, arg=%p)\n", cursor, as, arg);
+
+ // API docs at http://www.nongnu.org/libunwind/docs.html say we should
+ // handle a local address space but we're not doing the "remote" unwinding
+ // with local process accessors so punt on that.
+
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_init_remote was passed a non-remote address space");
+ return UNW_EINVAL;
+ }
+
+ unw_accessors_t* acc = unw_get_accessors(as);
+ if(!acc) {
+ ABORT("unw_get_accessors returned NULL");
+ return UNW_EINVAL;
+ }
+
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+
+ // use "placement new" to allocate UnwindCursor in the cursor buffer
+ // It isn't really necessary to use placement new in the remote API but we'll stay consistent
+ // with the rest of the code here.
+ switch ( remote->ras->getTargetArch() ) {
+ case UNW_TARGET_I386:
+ {
+ Registers_x86 *r = new Registers_x86;
+ OtherAddressSpace<Pointer32<LittleEndian> > *addrSpace = new OtherAddressSpace<Pointer32<LittleEndian> >(as, arg);
+ getRemoteContext (remote->ras, *r, arg);
+ unw_context_t *context = (unw_context_t*) r;
+ new ((void*)cursor) RemoteUnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >, Registers_x86>(*addrSpace, context, arg);
+ break;
+ }
+ break;
+ case UNW_TARGET_X86_64:
+ {
+ Registers_x86_64 *r = new Registers_x86_64;
+ OtherAddressSpace<Pointer64<LittleEndian> > *addrSpace = new OtherAddressSpace<Pointer64<LittleEndian> >(as, arg);
+ getRemoteContext (remote->ras, *r, arg);
+ unw_context_t *context = (unw_context_t*) r;
+ new ((void*)cursor) RemoteUnwindCursor<OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(*addrSpace, context, arg);
+ break;
+ }
+
+ case UNW_TARGET_PPC:
+ ABORT("ppc not supported for remote unwinds");
+ break;
+
+ case UNW_TARGET_ARM:
+ ABORT("arm not supported for remote unwinds");
+ break;
+
+ default:
+ return UNW_EUNSPEC;
+ }
+
+ AbstractRemoteUnwindCursor* co = (AbstractRemoteUnwindCursor*)cursor;
+ co->setRemoteContext(arg);
+
+ return UNW_ESUCCESS;
+}
+
+// The documentation disagrees about whether or not this returns a pointer. Now it does.
+EXPORT unw_accessors_t* unw_get_accessors(unw_addr_space_t as)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_get_accessors was passed a non-remote address space");
+ return NULL;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+
+ if(remote->type != UNW_REMOTE)
+ return NULL;
+
+ return remote->ras->getAccessors();
+}
+
+EXPORT unw_addr_space_t unw_create_addr_space(unw_accessors_t *ap, unw_targettype_t targarch)
+{
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)malloc(sizeof(unw_addr_space_remote));
+ remote->type = UNW_REMOTE;
+ remote->ras = new RemoteProcInfo(ap, targarch);
+ return (unw_addr_space_t)remote;
+}
+
+EXPORT void unw_flush_caches(unw_addr_space_t as)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_flush_caches was passed a non-remote address space");
+ return;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ remote->ras->flushAllCaches();
+
+ return;
+}
+
+EXPORT void unw_image_was_unloaded (unw_addr_space_t as, unw_word_t mh)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_image_was_unloaded was passed a non-remote address space");
+ return;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ remote->ras->flushCacheByMachHeader(mh);
+
+ return;
+}
+
+
+EXPORT int unw_set_caching_policy(unw_addr_space_t as, unw_caching_policy_t policy)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_set_caching_policy was passed a non-remote address space");
+ return UNW_EINVAL;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ return remote->ras->setCachingPolicy(policy);
+}
+
+EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&sThisAddressSpace;
+
+///
+/// delete an address_space object
+///
+EXPORT void unw_destroy_addr_space(unw_addr_space_t asp)
+{
+ if(asp->type != UNW_REMOTE) {
+ ABORT("unw_destroy_addr_space was passed a non-remote address space");
+ return;
+ }
+
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)asp;
+ delete remote->ras;
+}
+
+EXPORT void unw_set_logging_level(unw_addr_space_t as, FILE *f, unw_log_level_t level)
+{
+ if (as->type != UNW_REMOTE) {
+ ABORT("unw_set_logging_level was passed a non-remote address space");
+ return;
+ }
+
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ return remote->ras->setLoggingLevel(f, level);
+}
+
+
+EXPORT int unw_end_of_prologue_setup(unw_cursor_t* cursor, unw_word_t start, unw_word_t end, unw_word_t *endofprologue)
+{
+ AbstractRemoteUnwindCursor* co = (AbstractRemoteUnwindCursor*)cursor;
+ if (!co->remoteUnwindCursor())
+ ABORT("unw_end_of_prologue_setup called with a non-remote unwind cursor.");
+
+ return co->endOfPrologueInsns (start, end, endofprologue);
+}
+
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+#pragma mark Dynamic unwinding API
+
+#if !FOR_DYLD
+///
+/// SPI: walks cached dwarf entries
+///
+EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh))
+{
+ DEBUG_PRINT_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func);
+ DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
+}
+#endif // !FOR_DYLD
+
+#if !FOR_DYLD
+//
+// IPI: for __register_frame()
+//
+void _unw_add_dynamic_fde(unw_word_t fde)
+{
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char* message = CFI_Parser<LocalAddressSpace>::decodeFDE(sThisAddressSpace, (LocalAddressSpace::pint_t)fde, & fdeInfo, &cieInfo);
+ if ( message == NULL ) {
+ // dynamically registered FDEs don't have a mach_header group they are in. Use fde as mh_group
+ unw_word_t mh_group = fdeInfo.fdeStart;
+ DwarfFDECache<LocalAddressSpace>::add(mh_group, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart);
+ }
+ else {
+ DEBUG_MESSAGE("_unw_add_dynamic_fde: bad fde: %s", message);
+ }
+}
+
+//
+// IPI: for __deregister_frame()
+//
+void _unw_remove_dynamic_fde(unw_word_t fde)
+{
+ // fde is own mh_group
+ DwarfFDECache<LocalAddressSpace>::removeAllIn(fde);
+}
+#endif
+
+}; // namespace lldb_private
+
+#endif // __ppc__ || __i386__ || __x86_64__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s b/lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s
new file mode 100644
index 00000000000..8d3a451fd92
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s
@@ -0,0 +1,229 @@
+
+#if __i386__ || __x86_64__ || __ppc__
+
+ .text
+ .globl _unw_getcontext
+_unw_getcontext:
+
+#endif // __i386__ || __x86_64__ || __ppc__
+
+
+#if __i386__
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+#
+ push %eax
+ movl 8(%esp), %eax
+ movl %ebx, 4(%eax)
+ movl %ecx, 8(%eax)
+ movl %edx, 12(%eax)
+ movl %edi, 16(%eax)
+ movl %esi, 20(%eax)
+ movl %ebp, 24(%eax)
+ movl %esp, %edx
+ addl $8, %edx
+ movl %edx, 28(%eax) # store what sp was at call site as esp
+ # skip ss
+ # skip eflags
+ movl 4(%esp), %edx
+ movl %edx, 40(%eax) # store return address as eip
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+ movl (%esp), %edx
+ movl %edx, (%eax) # store original eax
+ popl %eax
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif __x86_64__
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in rdi
+#
+ movq %rax, (%rdi)
+ movq %rbx, 8(%rdi)
+ movq %rcx, 16(%rdi)
+ movq %rdx, 24(%rdi)
+ movq %rdi, 32(%rdi)
+ movq %rsi, 40(%rdi)
+ movq %rbp, 48(%rdi)
+ movq %rsp, 56(%rdi)
+ addq $8, 56(%rdi)
+ movq %r8, 64(%rdi)
+ movq %r9, 72(%rdi)
+ movq %r10, 80(%rdi)
+ movq %r11, 88(%rdi)
+ movq %r12, 96(%rdi)
+ movq %r13,104(%rdi)
+ movq %r14,112(%rdi)
+ movq %r15,120(%rdi)
+ movq (%rsp),%rsi
+ movq %rsi,128(%rdi) # store return address as rip
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif __ppc__
+
+;
+; extern int unw_getcontext(unw_context_t* thread_state)
+;
+; On entry:
+; thread_state pointer is in r3
+;
+ stw r0, 8(r3)
+ mflr r0
+ stw r0, 0(r3) ; store lr as ssr0
+ stw r1, 12(r3)
+ stw r2, 16(r3)
+ stw r3, 20(r3)
+ stw r4, 24(r3)
+ stw r5, 28(r3)
+ stw r6, 32(r3)
+ stw r7, 36(r3)
+ stw r8, 40(r3)
+ stw r9, 44(r3)
+ stw r10, 48(r3)
+ stw r11, 52(r3)
+ stw r12, 56(r3)
+ stw r13, 60(r3)
+ stw r14, 64(r3)
+ stw r15, 68(r3)
+ stw r16, 72(r3)
+ stw r17, 76(r3)
+ stw r18, 80(r3)
+ stw r19, 84(r3)
+ stw r20, 88(r3)
+ stw r21, 92(r3)
+ stw r22, 96(r3)
+ stw r23,100(r3)
+ stw r24,104(r3)
+ stw r25,108(r3)
+ stw r26,112(r3)
+ stw r27,116(r3)
+ stw r28,120(r3)
+ stw r29,124(r3)
+ stw r30,128(r3)
+ stw r31,132(r3)
+
+ ; save VRSave register
+ mfspr r0,256
+ stw r0,156(r3)
+ ; save CR registers
+ mfcr r0
+ stw r0,136(r3)
+ ; save CTR register
+ mfctr r0
+ stw r0,148(r3)
+
+ ; save float registers
+ stfd f0, 160(r3)
+ stfd f1, 168(r3)
+ stfd f2, 176(r3)
+ stfd f3, 184(r3)
+ stfd f4, 192(r3)
+ stfd f5, 200(r3)
+ stfd f6, 208(r3)
+ stfd f7, 216(r3)
+ stfd f8, 224(r3)
+ stfd f9, 232(r3)
+ stfd f10,240(r3)
+ stfd f11,248(r3)
+ stfd f12,256(r3)
+ stfd f13,264(r3)
+ stfd f14,272(r3)
+ stfd f15,280(r3)
+ stfd f16,288(r3)
+ stfd f17,296(r3)
+ stfd f18,304(r3)
+ stfd f19,312(r3)
+ stfd f20,320(r3)
+ stfd f21,328(r3)
+ stfd f22,336(r3)
+ stfd f23,344(r3)
+ stfd f24,352(r3)
+ stfd f25,360(r3)
+ stfd f26,368(r3)
+ stfd f27,376(r3)
+ stfd f28,384(r3)
+ stfd f29,392(r3)
+ stfd f30,400(r3)
+ stfd f31,408(r3)
+
+
+ ; save vector registers
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+
+#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
+ stvx _vec,0,r4 @\
+ lwz r5, 0(r4) @\
+ stw r5, _offset(r3) @\
+ lwz r5, 4(r4) @\
+ stw r5, _offset+4(r3) @\
+ lwz r5, 8(r4) @\
+ stw r5, _offset+8(r3) @\
+ lwz r5, 12(r4) @\
+ stw r5, _offset+12(r3)
+
+ SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
+ SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
+ SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
+ SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
+ SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
+ SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
+ SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
+ SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
+ SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
+ SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
+ SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
+ SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
+ SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
+ SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
+ SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
+ SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
+ SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
+ SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
+ SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
+ SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
+ SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
+ SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
+ SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
+ SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
+ SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
+ SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
+ SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
+ SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
+ SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
+ SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
+ SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
+ SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
+
+ li r3, 0 ; return UNW_ESUCCESS
+ blr
+
+
+
+#endif
+
OpenPOWER on IntegriCloud