Initial checkin of lldb code from internal Apple repo.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@105619 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
new file mode 100644
index 0000000..09cc09d
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -0,0 +1,578 @@
+//===-- ABIMacOSX_i386.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIMacOSX_i386.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *pluginName = "ABIMacOSX_i386";
+static const char *pluginDesc = "Mac OS X ABI for i386 targets";
+static const char *pluginShort = "abi.macosx-i386";
+
+size_t
+ABIMacOSX_i386::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+lldb_private::ABI *
+ABIMacOSX_i386::CreateInstance (const ConstString &triple)
+{
+ llvm::StringRef tripleStr(triple.GetCString());
+ llvm::Triple llvmTriple(tripleStr);
+
+ if (llvmTriple.getArch() != llvm::Triple::x86)
+ return NULL;
+
+ return new ABIMacOSX_i386;
+}
+
+bool
+ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+
+ uint32_t ebpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t eipID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t espID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // Make room for the argument on the stack
+
+ sp -= 4;
+
+ // Align the SP
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // Write the argument on the stack
+
+ uint32_t argU32 = arg & 0xffffffffull;
+ Error error;
+ if (thread.GetProcess().WriteMemory (sp, &argU32, sizeof(argU32), error) != sizeof(argU32))
+ return false;
+
+ // The return address is pushed onto the stack.
+
+ sp -= 4;
+ uint32_t returnAddressU32 = returnAddress;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(espID, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ebpID, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(eipID, functionAddress))
+ return false;
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+ Error error;
+ uint32_t ebpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t eipID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t espID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // Do the argument layout
+
+ std::vector <uint32_t> argLayout; // 4-byte chunks, as discussed in the ABI Function Call Guide
+
+ size_t numArgs = args.GetSize();
+ size_t index;
+
+ for (index = 0; index < numArgs; ++index)
+ {
+ Value *val = args.GetValueAtIndex(index);
+
+ if (!val)
+ return false;
+
+ switch (val->GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ {
+ Scalar &scalar = val->GetScalar();
+ switch (scalar.GetType())
+ {
+ case Scalar::e_void:
+ default:
+ return false;
+ case Scalar::e_sint:
+ case Scalar::e_uint:
+ case Scalar::e_slong:
+ case Scalar::e_ulong:
+ case Scalar::e_slonglong:
+ case Scalar::e_ulonglong:
+ {
+ uint64_t data = scalar.ULongLong();
+
+ switch (scalar.GetByteSize())
+ {
+ default:
+ return false;
+ case 1:
+ argLayout.push_back((uint32_t)(data & 0xffull));
+ break;
+ case 2:
+ argLayout.push_back((uint32_t)(data & 0xffffull));
+ break;
+ case 4:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ break;
+ case 8:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ argLayout.push_back((uint32_t)(data >> 32));
+ break;
+ }
+ }
+ break;
+ case Scalar::e_float:
+ {
+ float data = scalar.Float();
+ uint32_t dataRaw = *((uint32_t*)(&data));
+ argLayout.push_back(dataRaw);
+ }
+ break;
+ case Scalar::e_double:
+ {
+ double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ }
+ break;
+ case Scalar::e_long_double:
+ {
+ long double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ while ((argLayout.size() * 4) & 0xf)
+ argLayout.push_back(0);
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ argLayout.push_back(dataRaw[2]);
+ argLayout.push_back(dataRaw[3]);
+ }
+ break;
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ switch (val->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *val_type = val->GetOpaqueClangQualType();
+ uint32_t cstr_length;
+
+ if (ClangASTContext::IsCStringType (val_type, cstr_length))
+ {
+ const char *cstr = (const char*)val->GetScalar().ULongLong();
+ cstr_length = strlen(cstr);
+
+ // Push the string onto the stack immediately.
+
+ sp -= (cstr_length + 1);
+
+ if (thread.GetProcess().WriteMemory(sp, cstr, cstr_length + 1, error) != (cstr_length + 1))
+ return false;
+
+ // Put the address of the string into the argument array.
+
+ argLayout.push_back((uint32_t)(sp & 0xffffffff));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ default:
+ return false;
+ }
+ }
+
+ // Make room for the arguments on the stack
+
+ sp -= 4 * argLayout.size();
+
+ // Align the SP
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // Write the arguments on the stack
+
+ size_t numChunks = argLayout.size();
+
+ for (index = 0; index < numChunks; ++index)
+ if (thread.GetProcess().WriteMemory(sp + (index * 4), &argLayout[index], sizeof(uint32_t), error) != sizeof(uint32_t))
+ return false;
+
+ // The return address is pushed onto the stack.
+
+ sp -= 4;
+ uint32_t returnAddressU32 = returnAddress;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(espID, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ebpID, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(eipID, functionAddress))
+ return false;
+
+ return true;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Process &process,
+ addr_t ¤t_stack_argument)
+{
+ if (bit_width > 64)
+ return false; // Scalar can't hold large integer arguments
+
+ uint64_t arg_contents;
+ uint32_t read_data;
+ Error error;
+
+ if (bit_width > 32)
+ {
+ if (process.ReadMemory(current_stack_argument, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents = read_data;
+
+ if (process.ReadMemory(current_stack_argument + 4, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents |= ((uint64_t)read_data) << 32;
+
+ current_stack_argument += 8;
+ }
+ else {
+ if (process.ReadMemory(current_stack_argument, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents = read_data;
+
+ current_stack_argument += 4;
+ }
+
+ if (is_signed)
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (int8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (int16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (int32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (int64_t)arg_contents;
+ break;
+ }
+ }
+ else
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (uint8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (uint16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (uint32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (uint64_t)arg_contents;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Extract the Clang AST context from the PC so that we can figure out type
+ // sizes
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ if (!reg_ctx)
+ return false;
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 4; // jump over return address
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ switch (value->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *value_type = value->GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ ReadIntegerArgument(value->GetScalar(),
+ bit_width,
+ is_signed,
+ thread.GetProcess(),
+ current_stack_argument);
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ 32,
+ false,
+ thread.GetProcess(),
+ current_stack_argument);
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::GetReturnValue (Thread &thread,
+ Value &value) const
+{
+ switch (value.GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ // Extract the Clang AST context from the PC so that we can figure out type
+ // sizes
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ void *value_type = value.GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->reg;
+ unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->reg;
+
+ switch (bit_width)
+ {
+ default:
+ case 128:
+ // Scalar can't hold 128-bit literals, so we don't handle this
+ return false;
+ case 64:
+ uint64_t raw_value;
+ raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ else
+ value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ else
+ value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ else
+ value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ break;
+ }
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->reg;
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return false;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+void
+ABIMacOSX_i386::Initialize()
+{
+ PluginManager::RegisterPlugin (pluginName,
+ pluginDesc,
+ CreateInstance);
+}
+
+void
+ABIMacOSX_i386::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ABIMacOSX_i386::GetPluginName()
+{
+ return pluginName;
+}
+
+const char *
+ABIMacOSX_i386::GetShortPluginName()
+{
+ return pluginShort;
+}
+
+uint32_t
+ABIMacOSX_i386::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ABIMacOSX_i386::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ABIMacOSX_i386::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ABIMacOSX_i386::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
new file mode 100644
index 0000000..c27569b
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
@@ -0,0 +1,93 @@
+//===-- ABIMacOSX_i386.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_ABIMacOSX_i386_h_
+#define liblldb_ABIMacOSX_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Core/Value.h"
+
+namespace lldb_private {
+
+ class ABIMacOSX_i386 :
+ public lldb_private::ABI
+ {
+ public:
+ ~ABIMacOSX_i386() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const;
+
+ virtual bool
+ PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const;
+
+ virtual bool
+ GetArgumentValues (Thread &thread,
+ ValueList &values) const;
+
+ virtual bool
+ GetReturnValue (Thread &thread,
+ Value &value) const;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ABI *
+ CreateInstance (const ConstString &triple);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+ protected:
+ private:
+ ABIMacOSX_i386() : lldb_private::ABI() { } // Call CreateInstance instead.
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
new file mode 100644
index 0000000..004be60
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -0,0 +1,412 @@
+//===-- ABISysV_x86_64.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABISysV_x86_64.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *pluginName = "ABISysV_x86_64";
+static const char *pluginDesc = "System V ABI for x86_64 targets";
+static const char *pluginShort = "abi.sysv-x86_64";
+
+size_t
+ABISysV_x86_64::GetRedZoneSize () const
+{
+ return 128;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+lldb_private::ABI *
+ABISysV_x86_64::CreateInstance (const ConstString &triple)
+{
+ llvm::StringRef tripleStr(triple.GetCString());
+ llvm::Triple llvmTriple(tripleStr);
+
+ if (llvmTriple.getArch() != llvm::Triple::x86_64)
+ return NULL;
+
+ return new ABISysV_x86_64;
+}
+
+bool
+ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+
+ uint32_t rdiID = reg_ctx->GetRegisterInfoByName("rdi", 0)->reg;
+ uint32_t rbpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t ripID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t rspID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // The argument is in %rdi, and not on the stack.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(rdiID, arg))
+ return false;
+
+ // First, align the SP
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // The return address is pushed onto the stack.
+
+ sp -= 8;
+ uint64_t returnAddressU64 = returnAddress;
+ Error error;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU64, sizeof(returnAddressU64), error) != sizeof(returnAddressU64))
+ return false;
+
+ // %rsp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(rspID, sp))
+ return false;
+
+ // %rbp is set to a fake value, in our case 0x0000000000000000.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(rbpID, 0x000000000000000))
+ return false;
+
+ // %rip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ripID, functionAddress))
+ return false;
+
+ return true;
+}
+
+bool
+ABISysV_x86_64::PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const
+{
+ return false;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Thread &thread,
+ uint32_t *argument_register_ids,
+ unsigned int ¤t_argument_register,
+ addr_t ¤t_stack_argument)
+{
+ if (bit_width > 64)
+ return false; // Scalar can't hold large integer arguments
+
+ uint64_t arg_contents;
+
+ if (current_argument_register < 6)
+ {
+ arg_contents = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0);
+ current_argument_register++;
+ }
+ else
+ {
+ uint8_t arg_data[sizeof(arg_contents)];
+ Error error;
+ thread.GetProcess().ReadMemory(current_stack_argument, arg_data, sizeof(arg_contents), error);
+ DataExtractor arg_data_extractor(arg_data, sizeof(arg_contents), thread.GetProcess().GetByteOrder(), thread.GetProcess().GetAddressByteSize());
+ uint32_t offset = 0;
+ arg_contents = arg_data_extractor.GetMaxU64(&offset, bit_width / 8);
+ if (!offset)
+ return false;
+ current_stack_argument += (bit_width / 8);
+ }
+
+ if (is_signed)
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (int8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (int16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (int32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (int64_t)arg_contents;
+ break;
+ }
+ }
+ else
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (uint8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (uint16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (uint32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (uint64_t)arg_contents;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABISysV_x86_64::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // For now, assume that the types in the AST values come from the Target's
+ // scratch AST.
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ if (!reg_ctx)
+ return false;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 8; // jump over return address
+
+ uint32_t argument_register_ids[6];
+
+ argument_register_ids[0] = reg_ctx->GetRegisterInfoByName("rdi", 0)->reg;
+ argument_register_ids[1] = reg_ctx->GetRegisterInfoByName("rsi", 0)->reg;
+ argument_register_ids[2] = reg_ctx->GetRegisterInfoByName("rdx", 0)->reg;
+ argument_register_ids[3] = reg_ctx->GetRegisterInfoByName("rcx", 0)->reg;
+ argument_register_ids[4] = reg_ctx->GetRegisterInfoByName("r8", 0)->reg;
+ argument_register_ids[5] = reg_ctx->GetRegisterInfoByName("r9", 0)->reg;
+
+ unsigned int current_argument_register = 0;
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ switch (value->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *value_type = value->GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ ReadIntegerArgument(value->GetScalar(),
+ bit_width,
+ is_signed,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ 64,
+ false,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABISysV_x86_64::GetReturnValue (Thread &thread,
+ Value &value) const
+{
+ switch (value.GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *value_type = value.GetOpaqueClangQualType();
+ bool is_signed;
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ if (!reg_ctx)
+ return false;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ // For now, assume that the types in the AST values come from the Target's
+ // scratch AST.
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Extract the register context so we can read arguments from registers
+
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+ unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->reg;
+
+ switch (bit_width)
+ {
+ default:
+ case 128:
+ // Scalar can't hold 128-bit literals, so we don't handle this
+ return false;
+ case 64:
+ if (is_signed)
+ value.GetScalar() = (int64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
+ else
+ value.GetScalar() = (uint64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
+ else
+ value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
+ else
+ value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
+ else
+ value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
+ break;
+ }
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->reg;
+ value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+ }
+ else
+ {
+ // not handled yet
+ return false;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+void
+ABISysV_x86_64::Initialize()
+{
+ PluginManager::RegisterPlugin (pluginName,
+ pluginDesc,
+ CreateInstance);
+}
+
+void
+ABISysV_x86_64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ABISysV_x86_64::GetPluginName()
+{
+ return pluginName;
+}
+
+const char *
+ABISysV_x86_64::GetShortPluginName()
+{
+ return pluginShort;
+}
+
+uint32_t
+ABISysV_x86_64::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ABISysV_x86_64::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ABISysV_x86_64::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ABISysV_x86_64::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
new file mode 100644
index 0000000..b89d7c6
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -0,0 +1,92 @@
+//===-- ABISysV_x86_64.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_ABISysV_x86_64_h_
+#define liblldb_ABISysV_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+namespace lldb_private {
+
+class ABISysV_x86_64 :
+ public lldb_private::ABI
+{
+public:
+ ~ABISysV_x86_64() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const;
+
+ virtual bool
+ PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const;
+
+ virtual bool
+ GetArgumentValues (Thread &thread,
+ ValueList &values) const;
+
+ virtual bool
+ GetReturnValue (Thread &thread,
+ Value &value) const;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ABI *
+ CreateInstance (const ConstString &triple);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+protected:
+private:
+ ABISysV_x86_64() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp
new file mode 100644
index 0000000..db2d561
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp
@@ -0,0 +1,468 @@
+//===-- DisassemblerLLVM.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DisassemblerLLVM.h"
+
+#include "llvm-c/EnhancedDisassembly.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+
+#include <memory>
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static
+int DataExtractorByteReader(uint8_t *byte, uint64_t address, void *arg)
+{
+ DataExtractor &extractor = *((DataExtractor *)arg);
+
+ if (extractor.ValidOffset(address))
+ {
+ *byte = *(extractor.GetDataStart() + address);
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+namespace {
+ struct RegisterReaderArg {
+ const lldb::addr_t instructionPointer;
+ const EDDisassemblerRef disassembler;
+
+ RegisterReaderArg(lldb::addr_t ip,
+ EDDisassemblerRef dis) :
+ instructionPointer(ip),
+ disassembler(dis)
+ {
+ }
+ };
+}
+
+static int IPRegisterReader(uint64_t *value, unsigned regID, void* arg)
+{
+ uint64_t instructionPointer = ((RegisterReaderArg*)arg)->instructionPointer;
+ EDDisassemblerRef disassembler = ((RegisterReaderArg*)arg)->disassembler;
+
+ if(EDRegisterIsProgramCounter(disassembler, regID)) {
+ *value = instructionPointer;
+ return 0;
+ }
+
+ return -1;
+}
+
+DisassemblerLLVM::Instruction::Instruction(EDDisassemblerRef disassembler) :
+ Disassembler::Instruction (),
+ m_disassembler (disassembler)
+{
+}
+
+DisassemblerLLVM::Instruction::~Instruction()
+{
+}
+
+static void
+PadString(Stream *s, const std::string &str, size_t width)
+{
+ int diff = width - str.length();
+
+ if (diff > 0)
+ s->Printf("%s%*.*s", str.c_str(), diff, diff, "");
+ else
+ s->Printf("%s ", str.c_str());
+}
+
+void
+DisassemblerLLVM::Instruction::Dump
+(
+ Stream *s,
+ lldb::addr_t base_address,
+ DataExtractor *bytes,
+ uint32_t bytes_offset,
+ const lldb_private::ExecutionContext exe_ctx,
+ bool raw
+)
+{
+ const size_t opcodeColumnWidth = 7;
+ const size_t operandColumnWidth = 25;
+
+ // If we have an address, print it out
+ if (base_address != LLDB_INVALID_ADDRESS)
+ s->Printf("0x%llx: ", base_address);
+
+ // If we are supposed to show bytes, "bytes" will be non-NULL.
+ if (bytes)
+ {
+ uint32_t bytes_dumped = bytes->Dump(s, bytes_offset, eFormatBytes, 1, EDInstByteSize(m_inst), UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0) - bytes_offset;
+ // Allow for 8 bytes of opcodes normally
+ const uint32_t default_num_opcode_bytes = 9;
+ if (bytes_dumped * 3 < (default_num_opcode_bytes*3))
+ {
+ uint32_t indent_level = (default_num_opcode_bytes*3) - (bytes_dumped * 3);
+ s->Printf("%*.*s", indent_level, indent_level, "");
+ }
+ }
+
+ int numTokens = EDNumTokens(m_inst);
+
+ int currentOpIndex = -1;
+
+ RegisterReaderArg rra(base_address + EDInstByteSize(m_inst), m_disassembler);
+
+ lldb_private::Process *process = exe_ctx.process;
+
+ bool printTokenized = false;
+
+ if (numTokens != -1)
+ {
+ printTokenized = true;
+
+ // Handle the opcode column.
+
+ StreamString opcode;
+
+ int tokenIndex = 0;
+
+ EDTokenRef token;
+ const char *tokenStr;
+
+ if (EDGetToken(&token, m_inst, tokenIndex))
+ printTokenized = false;
+
+ if (!printTokenized || !EDTokenIsOpcode(token))
+ printTokenized = false;
+
+ if (!printTokenized || EDGetTokenString(&tokenStr, token))
+ printTokenized = false;
+
+ // Put the token string into our opcode string
+ opcode.PutCString(tokenStr);
+
+ // If anything follows, it probably starts with some whitespace. Skip it.
+
+ tokenIndex++;
+
+ if (printTokenized && tokenIndex < numTokens)
+ {
+ if(!printTokenized || EDGetToken(&token, m_inst, tokenIndex))
+ printTokenized = false;
+
+ if(!printTokenized || !EDTokenIsWhitespace(token))
+ printTokenized = false;
+ }
+
+ tokenIndex++;
+
+ // Handle the operands and the comment.
+
+ StreamString operands;
+ StreamString comment;
+
+ if (printTokenized)
+ {
+ bool show_token;
+
+ for (; tokenIndex < numTokens; ++tokenIndex)
+ {
+ if (EDGetToken(&token, m_inst, tokenIndex))
+ return;
+
+ if (raw)
+ {
+ show_token = true;
+ }
+ else
+ {
+ int operandIndex = EDOperandIndexForToken(token);
+
+ if (operandIndex >= 0)
+ {
+ if (operandIndex != currentOpIndex)
+ {
+ show_token = true;
+
+ currentOpIndex = operandIndex;
+ EDOperandRef operand;
+
+ if (!EDGetOperand(&operand, m_inst, currentOpIndex))
+ {
+ if (EDOperandIsMemory(operand))
+ {
+ uint64_t operand_value;
+
+ if (!EDEvaluateOperand(&operand_value, operand, IPRegisterReader, &rra))
+ {
+ if (EDInstIsBranch(m_inst))
+ {
+ operands.Printf("0x%llx ", operand_value);
+ show_token = false;
+ }
+ else
+ {
+ // Put the address value into the comment
+ comment.Printf("0x%llx ", operand_value);
+ }
+
+ lldb_private::Address so_addr;
+ if (process)
+ {
+ if (process->ResolveLoadAddress(operand_value, so_addr))
+ {
+ so_addr.Dump(&comment, process, Address::DumpStyleResolvedDescription, Address::DumpStyleSectionNameOffset);
+ }
+ }
+ } // EDEvaluateOperand
+ } // EDOperandIsMemory
+ } // EDGetOperand
+ } // operandIndex != currentOpIndex
+ } // operandIndex >= 0
+ } // else(raw)
+
+ if (show_token)
+ {
+ if(EDGetTokenString(&tokenStr, token))
+ {
+ printTokenized = false;
+ break;
+ }
+
+ operands.PutCString(tokenStr);
+ }
+ } // for (tokenIndex)
+
+ if (printTokenized)
+ {
+ if (operands.GetString().empty())
+ {
+ s->PutCString(opcode.GetString().c_str());
+ }
+ else
+ {
+ PadString(s, opcode.GetString(), opcodeColumnWidth);
+
+ if (comment.GetString().empty())
+ {
+ s->PutCString(operands.GetString().c_str());
+ }
+ else
+ {
+ PadString(s, operands.GetString(), operandColumnWidth);
+
+ s->PutCString("; ");
+ s->PutCString(comment.GetString().c_str());
+ } // else (comment.GetString().empty())
+ } // else (operands.GetString().empty())
+ } // printTokenized
+ } // for (tokenIndex)
+ } // numTokens != -1
+
+ if (!printTokenized)
+ {
+ const char *str;
+
+ if (EDGetInstString(&str, m_inst))
+ return;
+ else
+ s->PutCString(str);
+ }
+}
+
+bool
+DisassemblerLLVM::Instruction::DoesBranch() const
+{
+ return EDInstIsBranch(m_inst);
+}
+
+size_t
+DisassemblerLLVM::Instruction::GetByteSize() const
+{
+ return EDInstByteSize(m_inst);
+}
+
+size_t
+DisassemblerLLVM::Instruction::Extract(const DataExtractor &data, uint32_t data_offset)
+{
+ if (EDCreateInsts(&m_inst, 1, m_disassembler, DataExtractorByteReader, data_offset, (void*)(&data)))
+ return EDInstByteSize(m_inst);
+ else
+ return 0;
+}
+
+static inline const char *
+TripleForCPU(cpu_type_t cpuType)
+{
+ switch (cpuType)
+ {
+ default:
+ return NULL;
+ case CPU_TYPE_X86:
+ return "i386-unknown-unknown";
+ case CPU_TYPE_X86_64:
+ return "x86_64-unknown-unknown";
+ }
+}
+
+static inline EDAssemblySyntax_t
+SyntaxForCPU(cpu_type_t cpuType)
+{
+ switch (cpuType)
+ {
+ default:
+ return (EDAssemblySyntax_t)0; // default
+ case CPU_TYPE_X86:
+ case CPU_TYPE_X86_64:
+ return kEDAssemblySyntaxX86ATT;
+ }
+}
+
+Disassembler *
+DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
+{
+ cpu_type_t cpuType = arch.GetCPUType();
+
+ if (TripleForCPU(cpuType))
+ return new DisassemblerLLVM(arch);
+ else
+ return NULL;
+}
+
+DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
+ Disassembler(arch)
+{
+ cpu_type_t cpuType = arch.GetCPUType();
+
+ const char *triple = TripleForCPU(cpuType);
+ assert(triple && "Unhandled CPU type!");
+
+ EDAssemblySyntax_t syntax = SyntaxForCPU(cpuType);
+
+ assert(!EDGetDisassembler(&m_disassembler, triple, syntax) && "No disassembler created!");
+}
+
+DisassemblerLLVM::~DisassemblerLLVM()
+{
+}
+
+size_t
+DisassemblerLLVM::ParseInstructions
+(
+ const DataExtractor& data,
+ uint32_t data_offset,
+ uint32_t num_instructions,
+ lldb::addr_t base_addr
+)
+{
+ size_t total_inst_byte_size = 0;
+
+ m_instruction_list.Clear();
+
+ while (data.ValidOffset(data_offset) && num_instructions)
+ {
+ Instruction::shared_ptr inst_sp (new Instruction(m_disassembler));
+
+ size_t inst_byte_size = inst_sp->Extract(data, data_offset);
+
+ if (inst_byte_size == 0)
+ break;
+
+ m_instruction_list.AppendInstruction(inst_sp);
+
+ total_inst_byte_size += inst_byte_size;
+ data_offset += inst_byte_size;
+ num_instructions--;
+ }
+
+ return total_inst_byte_size;
+}
+
+void
+DisassemblerLLVM::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DisassemblerLLVM::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+DisassemblerLLVM::GetPluginNameStatic()
+{
+ return "disassembler.llvm";
+}
+
+const char *
+DisassemblerLLVM::GetPluginDescriptionStatic()
+{
+ return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+DisassemblerLLVM::GetPluginName()
+{
+ return "DisassemblerLLVM";
+}
+
+const char *
+DisassemblerLLVM::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DisassemblerLLVM::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVM.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVM.h
new file mode 100644
index 0000000..98166cb
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVM.h
@@ -0,0 +1,111 @@
+//===-- DisassemblerLLVM.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_DisassemblerLLVM_h_
+#define liblldb_DisassemblerLLVM_h_
+
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Host/Mutex.h"
+
+struct EDDisassembler;
+typedef EDDisassembler *EDDisassemblerRef;
+
+struct EDInst;
+typedef EDInst *EDInstRef;
+
+class DisassemblerLLVM : public lldb_private::Disassembler
+{
+public:
+ class Instruction : public lldb_private::Disassembler::Instruction
+ {
+ public:
+ Instruction(EDDisassemblerRef disassembler);
+
+ virtual
+ ~Instruction();
+
+ void
+ Dump (lldb_private::Stream *s,
+ lldb::addr_t base_address,
+ lldb_private::DataExtractor *bytes,
+ uint32_t bytes_offset,
+ const lldb_private::ExecutionContext exe_ctx,
+ bool raw);
+
+ bool
+ DoesBranch () const;
+
+ size_t
+ GetByteSize() const;
+
+ size_t
+ Extract (const lldb_private::DataExtractor &data,
+ uint32_t data_offset);
+
+ protected:
+ EDDisassemblerRef m_disassembler;
+ EDInstRef m_inst;
+ };
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::Disassembler *
+ CreateInstance(const lldb_private::ArchSpec &arch);
+
+
+ DisassemblerLLVM(const lldb_private::ArchSpec &arch);
+
+ virtual
+ ~DisassemblerLLVM();
+
+ size_t
+ ParseInstructions (const lldb_private::DataExtractor& data,
+ uint32_t data_offset,
+ uint32_t num_instructions,
+ lldb::addr_t base_addr);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+protected:
+ EDDisassemblerRef m_disassembler;
+};
+
+#endif // liblldb_DisassemblerLLVM_h_
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
new file mode 100644
index 0000000..a8dbf05
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
@@ -0,0 +1,1129 @@
+//===-- DynamicLoaderMacOSXDYLD.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/StackFrame.h"
+
+#include "DynamicLoaderMacOSXDYLD.h"
+#include "DynamicLoaderMacOSXDYLDLog.h"
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#include <stdio.h>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+/// FIXME - The ObjC Runtime trampoline handler doesn't really belong here.
+/// I am putting it here so I can invoke it in the Trampoline code here, but
+/// it should be moved to the ObjC Runtime support when it is set up.
+
+//----------------------------------------------------------------------
+// Create an instance of this class. This function is filled into
+// the plugin info class that gets handed out by the plugin factory and
+// allows the lldb to instantiate an instance of this class.
+//----------------------------------------------------------------------
+DynamicLoader *
+DynamicLoaderMacOSXDYLD::CreateInstance (Process* process)
+{
+ return new DynamicLoaderMacOSXDYLD (process);
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXDYLD::DynamicLoaderMacOSXDYLD (Process* process) :
+ DynamicLoader(process),
+ m_dyld(),
+ m_dyld_all_image_infos_addr(LLDB_INVALID_ADDRESS),
+ m_dyld_all_image_infos(),
+ m_break_id(LLDB_INVALID_BREAK_ID),
+ m_dyld_image_infos(),
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_objc_trampoline_handler_ap(NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXDYLD::~DynamicLoaderMacOSXDYLD()
+{
+ Clear(true);
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DidAttach ()
+{
+ PrivateInitialize(m_process);
+ if (NeedToLocateDYLD ())
+ LocateDYLD ();
+ SetNotificationBreakpoint ();
+ UpdateAllImageInfos();
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DidLaunch ()
+{
+ PrivateInitialize(m_process);
+ if (NeedToLocateDYLD ())
+ LocateDYLD ();
+ SetNotificationBreakpoint ();
+ UpdateAllImageInfos();
+}
+
+
+//----------------------------------------------------------------------
+// Clear out the state of this class.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Clear (bool clear_process)
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
+ m_process->ClearBreakpointSiteByID(m_break_id);
+
+ if (clear_process)
+ m_process = NULL;
+ m_dyld.Clear(false);
+ m_dyld_all_image_infos_addr = LLDB_INVALID_ADDRESS;
+ m_dyld_all_image_infos.Clear();
+ m_break_id = LLDB_INVALID_BREAK_ID;
+ m_dyld_image_infos.clear();
+}
+
+//----------------------------------------------------------------------
+// Check if we have found DYLD yet
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::DidSetNotificationBreakpoint() const
+{
+ return LLDB_BREAK_ID_IS_VALID (m_break_id);
+}
+
+//----------------------------------------------------------------------
+// Try and figure out where dyld is by first asking the Process
+// if it knows (which currently calls down in the the lldb::Process
+// to get the DYLD info (available on SnowLeopard only). If that fails,
+// then check in the default addresses.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::LocateDYLD()
+{
+ if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS)
+ m_dyld_all_image_infos_addr = m_process->GetImageInfoAddress ();
+
+ if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (ReadAllImageInfosStructure ())
+ {
+ if (m_dyld_all_image_infos.dyldImageLoadAddress != LLDB_INVALID_ADDRESS)
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos.dyldImageLoadAddress);
+ else
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos_addr & 0xfffffffffff00000ull);
+ }
+ }
+
+ // Check some default values
+ Module *executable = m_process->GetTarget().GetExecutableModule().get();
+
+ if (executable)
+ {
+ if (executable->GetArchitecture().GetAddressByteSize() == 8)
+ {
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x7fff5fc00000ull);
+ }
+#if defined (__arm__)
+ else
+ {
+ ArchSpec arm_arch("arm");
+ if (arm_arch == executable->Arch())
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x2fe00000);
+ }
+#endif
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x8fe00000);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Assume that dyld is in memory at ADDR and try to parse it's load
+// commands
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb::addr_t addr)
+{
+ DataExtractor data; // Load command data
+ if (ReadMachHeader (addr, &m_dyld.header, &data))
+ {
+ if (m_dyld.header.filetype == MH_DYLINKER)
+ {
+ m_dyld.address = addr;
+ ModuleSP dyld_module_sp;
+ if (ParseLoadCommands (data, m_dyld, &m_dyld.file_spec))
+ {
+ if (m_dyld.file_spec)
+ {
+ ArchSpec dyld_arch(m_dyld.header.cputype, m_dyld.header.cpusubtype);
+ dyld_module_sp = m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (m_dyld.file_spec);
+
+ if (dyld_module_sp.get() == NULL || dyld_module_sp->GetArchitecture() != dyld_arch)
+ {
+ dyld_module_sp = m_process->GetTarget().GetSharedModule (m_dyld.file_spec,
+ dyld_arch,
+ &m_dyld.uuid);
+ }
+
+ UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld);
+ }
+ }
+
+ if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS && dyld_module_sp.get())
+ {
+ static ConstString g_dyld_all_image_infos ("dyld_all_image_infos");
+ const Symbol *symbol = dyld_module_sp->FindFirstSymbolWithNameAndType (g_dyld_all_image_infos, eSymbolTypeData);
+ if (symbol)
+ m_dyld_all_image_infos_addr = symbol->GetValue().GetLoadAddress(m_process);
+ }
+
+ // Update all image infos
+ UpdateAllImageInfos();
+
+ // If we didn't have an executable before, but now we do, then the
+ // dyld module shared pointer might be unique and we may need to add
+ // it again (since Target::SetExecutableModule() will clear the
+ // images). So append the dyld module back to the list if it is
+ /// unique!
+ if (m_process->GetTarget().GetImages().AppendInNeeded (dyld_module_sp))
+ UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld);
+
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::NeedToLocateDYLD () const
+{
+ return m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::UpdateCommPageLoadAddress(Module *module)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ uint32_t num_sections = section_list->GetSize();
+ for (uint32_t i=0; i<num_sections; ++i)
+ {
+ Section* section = section_list->GetSectionAtIndex (i).get();
+ if (section)
+ {
+ const addr_t new_section_load_addr = section->GetFileAddress ();
+ const addr_t old_section_load_addr = m_process->GetSectionLoadAddress (section);
+ if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
+ old_section_load_addr != new_section_load_addr)
+ {
+ if (m_process->SectionLoaded (section, section->GetFileAddress ()))
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::UpdateImageLoadAddress (Module *module, struct DYLDImageInfo& info)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ // All sections listed in the dyld image info structure will all
+ // either be fixed up already, or they will all be off by a single
+ // slide amount that is determined by finding the first segment
+ // that is at file offset zero which also has bytes (a file size
+ // that is greater than zero) in the object file.
+
+ // Determine the slide amount (if any)
+ info.slide = 0;
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ Section *section = section_list->GetSectionAtIndex (sect_idx).get();
+ if (section)
+ {
+ // Find the first section that begins at file offset zero
+ // a file size (skip page zero).
+ if (section->GetFileOffset() == 0 && section->GetFileSize() > 0)
+ {
+ // We have now found the section, lets match it up
+ // with the section in the dyld image info structure.
+ const Segment *dyld_segment = info.FindSegment (section->GetName());
+ if (dyld_segment)
+ info.slide = info.address - dyld_segment->addr;
+ // We have found the slide amount, so we can exit
+ // this for loop.
+ break;
+ }
+ }
+ }
+
+ // We now know the slide amount, so go through all sections
+ // and update the load addresses with the correct values.
+ uint32_t num_segments = info.segments.size();
+ for (uint32_t i=0; i<num_segments; ++i)
+ {
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+ assert (section_sp.get() != NULL);
+ const addr_t new_section_load_addr = info.segments[i].addr + info.slide;
+ const addr_t old_section_load_addr = m_process->GetSectionLoadAddress (section_sp.get());
+ if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
+ old_section_load_addr != new_section_load_addr)
+ {
+ if (m_process->SectionLoaded (section_sp.get(), new_section_load_addr))
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::UnloadImageLoadAddress (Module *module, struct DYLDImageInfo& info)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ uint32_t num_segments = info.segments.size();
+ for (uint32_t i=0; i<num_segments; ++i)
+ {
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+ assert (section_sp.get() != NULL);
+ const addr_t old_section_load_addr = info.segments[i].addr + info.slide;
+ if (m_process->SectionUnloaded (section_sp.get(), old_section_load_addr))
+ changed = true;
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when our DYLD notification
+// breakpoint gets hit. We update all of our image infos and then
+// let our super class DynamicLoader class decide if we should stop
+// or not (based on global preference).
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::NotifyBreakpointHit (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
+{
+ // Let the event know that the images have changed
+ DynamicLoaderMacOSXDYLD* dyld_instance = (DynamicLoaderMacOSXDYLD*) baton;
+ dyld_instance->UpdateAllImageInfos();
+ // Return true to stop the target, false to just let the target run
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+bool
+DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure ()
+{
+ Mutex::Locker locker(m_mutex);
+ m_dyld_all_image_infos.Clear();
+ if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS)
+ {
+ const ByteOrder endian = m_process->GetByteOrder();
+ const uint32_t addr_size = m_process->GetAddressByteSize();
+ uint8_t buf[256];
+ const size_t count = 2 * sizeof(uint32_t) + // version + dylib_info_count
+ addr_size * 2 + // dylib_info_addr + notification
+ 2 + addr_size - 2 + // processDetachedFromSharedRegion + libSystemInitialized + pad
+ addr_size; // dyldImageLoadAddress
+ Error error;
+ const size_t bytes_read = m_process->ReadMemory (m_dyld_all_image_infos_addr, buf, count, error);
+ if (bytes_read == count)
+ {
+ DataExtractor data(buf, count, endian, addr_size);
+ uint32_t offset = 0;
+ m_dyld_all_image_infos.version = data.GetU32(&offset);
+ m_dyld_all_image_infos.dylib_info_count = data.GetU32(&offset);
+ m_dyld_all_image_infos.dylib_info_addr = data.GetPointer(&offset);
+ m_dyld_all_image_infos.notification = data.GetPointer(&offset);
+ m_dyld_all_image_infos.processDetachedFromSharedRegion = data.GetU8(&offset);
+ if (m_dyld_all_image_infos.version >= 2)
+ {
+ m_dyld_all_image_infos.libSystemInitialized = data.GetU8(&offset);
+ // Adjust for padding.
+ offset += addr_size - 2;
+ m_dyld_all_image_infos.dyldImageLoadAddress = data.GetPointer(&offset);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// If we have found where the "_dyld_all_image_infos" lives in memory,
+// read the current info from it, and then update all image load
+// addresses (or lack thereof).
+//----------------------------------------------------------------------
+uint32_t
+DynamicLoaderMacOSXDYLD::UpdateAllImageInfos()
+{
+ if (ReadAllImageInfosStructure ())
+ {
+ Mutex::Locker locker(m_mutex);
+ uint32_t idx;
+ Error error;
+ uint32_t i = 0;
+ DYLDImageInfo::collection old_dyld_all_image_infos;
+ old_dyld_all_image_infos.swap(m_dyld_image_infos);
+
+ // If we made it here, we are assuming that the all dylib info data should
+ // be valid, lets read the info array.
+ const ByteOrder endian = m_process->GetByteOrder();
+ const uint32_t addr_size = m_process->GetAddressByteSize();
+
+ if (m_dyld_all_image_infos.dylib_info_count > 0)
+ {
+ if (m_dyld_all_image_infos.dylib_info_addr == 0)
+ {
+ // DYLD is updating the images right now...
+ }
+ else
+ {
+ m_dyld_image_infos.resize(m_dyld_all_image_infos.dylib_info_count);
+ const size_t count = m_dyld_image_infos.size() * 3 * addr_size;
+ DataBufferHeap info_data(count, 0);
+ Error error;
+ const size_t bytes_read = m_process->ReadMemory (m_dyld_all_image_infos.dylib_info_addr,
+ info_data.GetBytes(),
+ info_data.GetByteSize(),
+ error);
+ if (bytes_read == count)
+ {
+ uint32_t info_data_offset = 0;
+ DataExtractor info_data_ref(info_data.GetBytes(), info_data.GetByteSize(), endian, addr_size);
+ for (i = 0; info_data_ref.ValidOffset(info_data_offset); i++)
+ {
+ assert (i < m_dyld_image_infos.size());
+ m_dyld_image_infos[i].address = info_data_ref.GetPointer(&info_data_offset);
+ lldb::addr_t path_addr = info_data_ref.GetPointer(&info_data_offset);
+ m_dyld_image_infos[i].mod_date = info_data_ref.GetPointer(&info_data_offset);
+
+ char raw_path[PATH_MAX];
+ m_process->ReadMemory (path_addr, raw_path, sizeof(raw_path), error);
+ m_dyld_image_infos[i].file_spec.SetFile(raw_path);
+ }
+ assert(i == m_dyld_all_image_infos.dylib_info_count);
+
+ UpdateAllImageInfosHeaderAndLoadCommands();
+ }
+ else
+ {
+ DEBUG_PRINTF( "unable to read all data for all_dylib_infos.");
+ m_dyld_image_infos.clear();
+ }
+ }
+ }
+ else
+ {
+ m_dyld_image_infos.clear();
+ }
+
+ // If our new list is smaller than our old list, we have unloaded
+ // some shared libraries
+ if (m_dyld_image_infos.size() < old_dyld_all_image_infos.size())
+ {
+ ModuleList unloaded_module_list;
+ for (idx = m_dyld_image_infos.size(); idx < old_dyld_all_image_infos.size(); ++idx)
+ {
+ ModuleSP unload_image_module_sp(m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (old_dyld_all_image_infos[idx].file_spec));
+ if (unload_image_module_sp.get())
+ {
+ if (UnloadImageLoadAddress (unload_image_module_sp.get(), old_dyld_all_image_infos[idx]))
+ unloaded_module_list.AppendInNeeded (unload_image_module_sp);
+ }
+ }
+ if (unloaded_module_list.GetSize() > 0)
+ m_process->GetTarget().ModulesDidUnload (unloaded_module_list);
+ }
+ }
+ else
+ {
+ m_dyld_image_infos.clear();
+ }
+
+ const uint32_t num_dylibs = m_dyld_image_infos.size();
+ if (num_dylibs > 0)
+ {
+ ModuleList loaded_module_list;
+ for (uint32_t idx = 0; idx<num_dylibs; ++idx)
+ {
+ ArchSpec arch_spec(m_dyld_image_infos[idx].header.cputype, m_dyld_image_infos[idx].header.cpusubtype);
+ ModuleSP image_module_sp(m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (m_dyld_image_infos[idx].file_spec));
+ if (image_module_sp.get() == NULL || image_module_sp->GetArchitecture() != arch_spec)
+ {
+ image_module_sp = m_process->GetTarget().GetSharedModule (m_dyld_image_infos[idx].file_spec,
+ arch_spec,
+ &m_dyld_image_infos[idx].uuid);
+ }
+
+ if (image_module_sp)
+ {
+ ObjectFile *objfile = image_module_sp->GetObjectFile ();
+ if (objfile)
+ {
+ SectionList *sections = objfile->GetSectionList();
+ if (sections)
+ {
+ ConstString commpage_dbstr("__commpage");
+ Section *commpage_section = sections->FindSectionByName(commpage_dbstr).get();
+ if (commpage_section)
+ {
+ FileSpec objfile_file_spec(objfile->GetFileSpec());
+ ModuleSP commpage_image_module_sp(m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (objfile_file_spec, &commpage_dbstr));
+ if (commpage_image_module_sp.get() == NULL)
+ {
+ commpage_image_module_sp = m_process->GetTarget().GetSharedModule (m_dyld_image_infos[idx].file_spec,
+ arch_spec,
+ &m_dyld_image_infos[idx].uuid,
+ &commpage_dbstr,
+ objfile->GetOffset() + commpage_section->GetOffset());
+ UpdateCommPageLoadAddress(commpage_image_module_sp.get());
+ }
+ }
+ }
+ }
+
+ // UpdateImageLoadAddress will return true if any segments
+ // change load address. We need to check this so we don't
+ // mention that all loaded shared libraries are newly loaded
+ // each time we hit out dyld breakpoint since dyld will list all
+ // shared libraries each time.
+ if (UpdateImageLoadAddress (image_module_sp.get(), m_dyld_image_infos[idx]))
+ {
+ loaded_module_list.AppendInNeeded (image_module_sp);
+ }
+ }
+ }
+ PutToLog(DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (1));
+ if (loaded_module_list.GetSize() > 0)
+ {
+ // FIXME: This should really be in the Runtime handlers class, which should get
+ // called by the target's ModulesDidLoad, but we're doing it all locally for now
+ // to save time.
+ // Also, I'm assuming there can be only one libobjc dylib loaded...
+
+ if (m_objc_trampoline_handler_ap.get() == NULL)
+ {
+ size_t num_modules = loaded_module_list.GetSize();
+ for (int i = 0; i < num_modules; i++)
+ {
+ if (ObjCTrampolineHandler::ModuleIsObjCLibrary (loaded_module_list.GetModuleAtIndex (i)))
+ {
+ m_objc_trampoline_handler_ap.reset (new ObjCTrampolineHandler(m_process->GetSP(), loaded_module_list.GetModuleAtIndex (i)));
+ break;
+ }
+ }
+ }
+ m_process->GetTarget().ModulesDidLoad (loaded_module_list);
+ }
+ }
+ return m_dyld_image_infos.size();
+}
+
+//----------------------------------------------------------------------
+// Read a mach_header at ADDR into HEADER, and also fill in the load
+// command data into LOAD_COMMAND_DATA if it is non-NULL.
+//
+// Returns true if we succeed, false if we fail for any reason.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::ReadMachHeader (lldb::addr_t addr, struct mach_header *header, DataExtractor *load_command_data)
+{
+ DataBufferHeap header_bytes(sizeof(struct mach_header), 0);
+ Error error;
+ size_t bytes_read = m_process->ReadMemory (addr,
+ header_bytes.GetBytes(),
+ header_bytes.GetByteSize(),
+ error);
+ if (bytes_read == sizeof(struct mach_header))
+ {
+ uint32_t offset = 0;
+ ::memset (header, 0, sizeof(header));
+
+ // Get the magic byte unswapped so we can figure out what we are dealing with
+ DataExtractor data(header_bytes.GetBytes(), header_bytes.GetByteSize(), eByteOrderHost, 4);
+ header->magic = data.GetU32(&offset);
+ lldb::addr_t load_cmd_addr = addr;
+ data.SetByteOrder(DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(header->magic));
+ switch (header->magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ data.SetAddressByteSize(4);
+ load_cmd_addr += sizeof(struct mach_header);
+ break;
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ data.SetAddressByteSize(8);
+ load_cmd_addr += sizeof(struct mach_header_64);
+ break;
+
+ default:
+ return false;
+ }
+
+ // Read the rest of dyld's mach header
+ if (data.GetU32(&offset, &header->cputype, (sizeof(struct mach_header)/sizeof(uint32_t)) - 1))
+ {
+ if (load_command_data == NULL)
+ return true; // We were able to read the mach_header and weren't asked to read the load command bytes
+
+ DataBufferSP load_cmd_data_sp(new DataBufferHeap(header->sizeofcmds, 0));
+
+ size_t load_cmd_bytes_read = m_process->ReadMemory (load_cmd_addr,
+ load_cmd_data_sp->GetBytes(),
+ load_cmd_data_sp->GetByteSize(),
+ error);
+
+ if (load_cmd_bytes_read == header->sizeofcmds)
+ {
+ // Set the load command data and also set the correct endian
+ // swap settings and the correct address size
+ load_command_data->SetData(load_cmd_data_sp, 0, header->sizeofcmds);
+ load_command_data->SetByteOrder(data.GetByteOrder());
+ load_command_data->SetAddressByteSize(data.GetAddressByteSize());
+ return true; // We successfully read the mach_header and the load command data
+ }
+
+ return false; // We weren't able to read the load command data
+ }
+ }
+ return false; // We failed the read the mach_header
+}
+
+
+//----------------------------------------------------------------------
+// Parse the load commands for an image
+//----------------------------------------------------------------------
+uint32_t
+DynamicLoaderMacOSXDYLD::ParseLoadCommands (const DataExtractor& data, struct DYLDImageInfo& dylib_info, FileSpec *lc_id_dylinker)
+{
+ uint32_t offset = 0;
+ uint32_t cmd_idx;
+ Segment segment;
+ dylib_info.Clear (true);
+
+ for (cmd_idx = 0; cmd_idx < dylib_info.header.ncmds; cmd_idx++)
+ {
+ // Clear out any load command specific data from DYLIB_INFO since
+ // we are about to read it.
+
+ if (data.ValidOffsetForDataOfSize (offset, sizeof(struct load_command)))
+ {
+ struct load_command load_cmd;
+ uint32_t load_cmd_offset = offset;
+ load_cmd.cmd = data.GetU32 (&offset);
+ load_cmd.cmdsize = data.GetU32 (&offset);
+ switch (load_cmd.cmd)
+ {
+ case LC_SEGMENT:
+ {
+ segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16);
+ segment.addr = data.GetU32 (&offset);
+ segment.size = data.GetU32 (&offset);
+ dylib_info.segments.push_back (segment);
+ }
+ break;
+
+ case LC_SEGMENT_64:
+ {
+ segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16);
+ segment.addr = data.GetU64 (&offset);
+ segment.size = data.GetU64 (&offset);
+ dylib_info.segments.push_back (segment);
+ }
+ break;
+
+ case LC_ID_DYLINKER:
+ if (lc_id_dylinker)
+ {
+ uint32_t name_offset = load_cmd_offset + data.GetU32 (&offset);
+ const char *path = data.PeekCStr (name_offset);
+ lc_id_dylinker->SetFile (path);
+ }
+ break;
+
+ case LC_UUID:
+ dylib_info.uuid.SetBytes(data.GetData (&offset, 16));
+ break;
+
+ default:
+ break;
+ }
+ // Set offset to be the beginning of the next load command.
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
+ }
+ return cmd_idx;
+}
+
+//----------------------------------------------------------------------
+// Read the mach_header and load commands for each image that the
+// _dyld_all_image_infos structure points to and cache the results.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::UpdateAllImageInfosHeaderAndLoadCommands()
+{
+ uint32_t exe_idx = UINT32_MAX;
+ // Read any UUID values that we can get
+ for (uint32_t i = 0; i < m_dyld_all_image_infos.dylib_info_count; i++)
+ {
+ if (!m_dyld_image_infos[i].UUIDValid())
+ {
+ DataExtractor data; // Load command data
+ if (!ReadMachHeader (m_dyld_image_infos[i].address, &m_dyld_image_infos[i].header, &data))
+ continue;
+
+ ParseLoadCommands (data, m_dyld_image_infos[i], NULL);
+
+ if (m_dyld_image_infos[i].header.filetype == MH_EXECUTE)
+ exe_idx = i;
+ }
+ }
+
+ if (exe_idx < m_dyld_image_infos.size())
+ {
+ bool set_executable = false;
+ ArchSpec dyld_exe_arch_spec(m_dyld_image_infos[exe_idx].header.cputype, m_dyld_image_infos[exe_idx].header.cpusubtype);
+ ModuleSP exe_module_sp(m_process->GetTarget().GetExecutableModule());
+ if (exe_module_sp.get())
+ {
+ if (exe_module_sp->GetFileSpec() != m_dyld_image_infos[exe_idx].file_spec ||
+ exe_module_sp->GetArchitecture() != dyld_exe_arch_spec)
+ set_executable = true;
+ }
+ else
+ set_executable = true;
+
+ if (set_executable)
+ {
+ exe_module_sp = m_process->GetTarget().GetSharedModule (m_dyld_image_infos[exe_idx].file_spec,
+ dyld_exe_arch_spec,
+ &m_dyld_image_infos[exe_idx].uuid);
+ if (exe_module_sp.get())
+ {
+ // If we found the file where it purported to be, then it should
+ // be safe to load dependent images.
+ bool get_dependent_images = exe_module_sp->GetFileSpec() == m_dyld_image_infos[exe_idx].file_spec;
+
+ m_process->GetTarget().SetExecutableModule (exe_module_sp, get_dependent_images);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump a Segment to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Segment::PutToLog (Log *log, lldb::addr_t slide) const
+{
+ if (log)
+ log->Printf("\t\t%16s [0x%16.16llx - 0x%16.16llx)", name.AsCString(""), addr + slide, addr + slide + size);
+}
+
+const DynamicLoaderMacOSXDYLD::Segment *
+DynamicLoaderMacOSXDYLD::DYLDImageInfo::FindSegment (const ConstString &name) const
+{
+ const size_t num_segments = segments.size();
+ for (size_t i=0; i<num_segments; ++i)
+ {
+ if (segments[i].name == name)
+ return &segments[i];
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Dump an image info structure to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DYLDImageInfo::PutToLog (Log *log) const
+{
+ if (log == NULL)
+ return;
+ uint8_t *u = (uint8_t *)uuid.GetBytes();
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ if (u)
+ {
+ log->Printf("\t modtime=0x%8.8llx uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s/%s' (UNLOADED)",
+ mod_date,
+ u[ 0], u[ 1], u[ 2], u[ 3],
+ u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11],
+ u[12], u[13], u[14], u[15],
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+ }
+ else
+ log->Printf("\t modtime=0x%8.8llx path='%s/%s' (UNLOADED)",
+ mod_date,
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+ }
+ else
+ {
+ if (u)
+ {
+ log->Printf("\taddress=0x%16.16llx modtime=0x%8.8llx uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s/%s'",
+ address,
+ mod_date,
+ u[ 0], u[ 1], u[ 2], u[ 3],
+ u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11],
+ u[12], u[13], u[14], u[15],
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+ }
+ else
+ {
+ log->Printf("\taddress=0x%16.16llx modtime=0x%8.8llx path='%s/%s'",
+ address,
+ mod_date,
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+
+ }
+ for (uint32_t i=0; i<segments.size(); ++i)
+ segments[i].PutToLog(log, slide);
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump the _dyld_all_image_infos members and all current image infos
+// that we have parsed to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::PutToLog(Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ Mutex::Locker locker(m_mutex);
+ log->Printf("dyld_all_image_infos = { version=%d, count=%d, addr=0x%8.8llx, notify=0x%8.8llx }",
+ m_dyld_all_image_infos.version,
+ m_dyld_all_image_infos.dylib_info_count,
+ (uint64_t)m_dyld_all_image_infos.dylib_info_addr,
+ (uint64_t)m_dyld_all_image_infos.notification);
+ size_t i;
+ const size_t count = m_dyld_image_infos.size();
+ if (count > 0)
+ {
+ log->Printf("\tdyld_image_infos");
+ for (i = 0; i<count; i++)
+ m_dyld_image_infos[i].PutToLog(log);
+ }
+}
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when the process state
+// changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Initialize(void *baton, Process *process)
+{
+ ((DynamicLoaderMacOSXDYLD*)baton)->PrivateInitialize(process);
+}
+
+void
+DynamicLoaderMacOSXDYLD::PrivateInitialize(Process *process)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ Clear(true);
+ m_process = process;
+}
+
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when the process state
+// changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::ProcessStateChanged(void *baton, Process *process, StateType state)
+{
+ ((DynamicLoaderMacOSXDYLD*)baton)->PrivateProcessStateChanged(process, state);
+}
+
+bool
+DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint ()
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ if (m_break_id == LLDB_INVALID_BREAK_ID)
+ {
+ if (m_dyld_all_image_infos.notification != LLDB_INVALID_ADDRESS)
+ {
+ Address so_addr;
+ // Set the notification breakpoint and install a breakpoint
+ // callback function that will get called each time the
+ // breakpoint gets hit. We will use this to track when shared
+ // libraries get loaded/unloaded.
+
+ if (m_process->ResolveLoadAddress(m_dyld_all_image_infos.notification, so_addr))
+ {
+ Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint (so_addr, true).get();
+ dyld_break->SetCallback (DynamicLoaderMacOSXDYLD::NotifyBreakpointHit, this, true);
+ m_break_id = dyld_break->GetID();
+ }
+ }
+ }
+ return m_break_id != LLDB_INVALID_BREAK_ID;
+}
+
+//----------------------------------------------------------------------Target.h
+
+// Member function that gets called when the process state changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::PrivateProcessStateChanged (Process *process, StateType state)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s(%s)\n", __FUNCTION__, StateAsCString(state));
+ switch (state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateDetached:
+ Clear(false);
+ break;
+
+ case eStateStopped:
+ // Keep trying find dyld and set our notification breakpoint each time
+ // we stop until we succeed
+ if (!DidSetNotificationBreakpoint () && m_process->IsAlive())
+ {
+ if (NeedToLocateDYLD ())
+ LocateDYLD ();
+
+ SetNotificationBreakpoint ();
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+
+ default:
+ break;
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
+{
+ ThreadPlanSP thread_plan_sp;
+ StackFrame *current_frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext ¤t_context = current_frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *current_symbol = current_context.symbol;
+
+ if (current_symbol != NULL)
+ {
+ if (current_symbol->IsTrampoline())
+ {
+ const ConstString &trampoline_name = current_symbol->GetMangled().GetName();
+ if (trampoline_name)
+ {
+ SymbolContextList target_symbols;
+ ModuleList &images = thread.GetProcess().GetTarget().GetImages();
+ images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, target_symbols);
+ // FIXME - Make the Run to Address take multiple addresses, and
+ // run to any of them.
+ if (target_symbols.GetSize() == 1)
+ {
+ SymbolContext context;
+ AddressRange addr_range;
+ if (target_symbols.GetContextAtIndex(0, context))
+ {
+ context.GetAddressRange (eSymbolContextEverything, addr_range);
+ thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addr_range.GetBaseAddress(), stop_others));
+ }
+ }
+ else if (target_symbols.GetSize() > 1)
+ {
+ Log *log = DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (1);
+ if (log)
+ {
+ log->Printf ("Found more than one symbol for trampoline target: \"%s\"", trampoline_name.AsCString());
+ }
+ }
+ else
+ {
+ Log *log = DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (1);
+ if (log)
+ {
+ log->Printf ("Could not find symbol for trampoline target: \"%s\"", trampoline_name.AsCString());
+ }
+ }
+ }
+ }
+ }
+
+ if (thread_plan_sp == NULL && m_objc_trampoline_handler_ap.get())
+ thread_plan_sp = m_objc_trampoline_handler_ap->GetStepThroughDispatchPlan (thread, stop_others);
+
+ return thread_plan_sp;
+}
+
+void
+DynamicLoaderMacOSXDYLD::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderMacOSXDYLD::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+DynamicLoaderMacOSXDYLD::GetPluginNameStatic()
+{
+ return "dynamic-loader.macosx-dyld";
+}
+
+const char *
+DynamicLoaderMacOSXDYLD::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library loads/unloads in MacOSX user processes.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+DynamicLoaderMacOSXDYLD::GetPluginName()
+{
+ return "DynamicLoaderMacOSXDYLD";
+}
+
+const char *
+DynamicLoaderMacOSXDYLD::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DynamicLoaderMacOSXDYLD::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+DynamicLoaderMacOSXDYLD::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+DynamicLoaderMacOSXDYLD::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+DynamicLoaderMacOSXDYLD::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
new file mode 100644
index 0000000..724a8b6
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
@@ -0,0 +1,360 @@
+//===-- DynamicLoaderMacOSXDYLD.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_DynamicLoaderMacOSXDYLD_h_
+#define liblldb_DynamicLoaderMacOSXDYLD_h_
+
+// C Includes
+#include <mach-o/loader.h>
+
+// C++ Includes
+#include <map>
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "ObjCTrampolineHandler.h"
+
+class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoader
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance (lldb_private::Process *process);
+
+ DynamicLoaderMacOSXDYLD (lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderMacOSXDYLD ();
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach ();
+
+ virtual void
+ DidLaunch ();
+
+ //------------------------------------------------------------------
+ // Process::Notifications callback functions
+ //------------------------------------------------------------------
+ static void
+ Initialize (void *baton,
+ lldb_private::Process *process);
+
+ static void
+ ProcessStateChanged (void *baton,
+ lldb_private::Process *process,
+ lldb::StateType state);
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan (lldb_private::Thread &thread,
+ bool stop_others);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+
+protected:
+ void
+ PrivateInitialize (lldb_private::Process *process);
+
+ void
+ PrivateProcessStateChanged (lldb_private::Process *process,
+ lldb::StateType state);
+ bool
+ LocateDYLD ();
+
+ bool
+ DidSetNotificationBreakpoint () const;
+
+ void
+ Clear (bool clear_process);
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ bool
+ ReadDYLDInfoFromMemoryAndSetNotificationCallback (lldb::addr_t addr);
+
+ uint32_t
+ UpdateAllImageInfos ();
+
+ static bool
+ NotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+ void
+ UpdateAllImageInfosHeaderAndLoadCommands ();
+
+ bool
+ UpdateCommPageLoadAddress (lldb_private::Module *module);
+
+ uint32_t
+ AddrByteSize()
+ {
+ switch (m_dyld.header.magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ return 4;
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ return 8;
+
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ static lldb::ByteOrder
+ GetByteOrderFromMagic (uint32_t magic)
+ {
+ switch (magic)
+ {
+ case MH_MAGIC:
+ case MH_MAGIC_64:
+ return lldb::eByteOrderHost;
+
+ case MH_CIGAM:
+ case MH_CIGAM_64:
+ if (lldb::eByteOrderHost == lldb::eByteOrderBig)
+ return lldb::eByteOrderLittle;
+ else
+ return lldb::eByteOrderBig;
+
+ default:
+ break;
+ }
+ return lldb::eByteOrderInvalid;
+ }
+
+ bool
+ ReadMachHeader (lldb::addr_t addr,
+ struct mach_header *header,
+ lldb_private::DataExtractor *load_command_data);
+ class Segment
+ {
+ public:
+
+ Segment() :
+ name(),
+ addr(LLDB_INVALID_ADDRESS),
+ size(0)
+ {
+ }
+
+ lldb_private::ConstString name;
+ lldb::addr_t addr;
+ lldb::addr_t size;
+
+ bool
+ operator==(const Segment& rhs) const
+ {
+ return name == rhs.name && addr == rhs.addr && size == rhs.size;
+ }
+
+ void
+ PutToLog (lldb_private::Log *log,
+ lldb::addr_t slide) const;
+
+ };
+
+ struct DYLDImageInfo
+ {
+ lldb::addr_t address; // Address of mach header for this dylib
+ lldb::addr_t slide; // The amount to slide all segments by if there is a global slide.
+ lldb::addr_t mod_date; // Modification date for this dylib
+ lldb_private::FileSpec file_spec; // Resolved path for this dylib
+ lldb_private::UUID uuid; // UUID for this dylib if it has one, else all zeros
+ struct mach_header header; // The mach header for this image
+ std::vector<Segment> segments; // All segment vmaddr and vmsize pairs for this executable (from memory of inferior)
+
+ DYLDImageInfo() :
+ address(LLDB_INVALID_ADDRESS),
+ slide(0),
+ mod_date(0),
+ file_spec(),
+ uuid(),
+ header(),
+ segments()
+ {
+ }
+
+ void
+ Clear(bool load_cmd_data_only)
+ {
+ if (!load_cmd_data_only)
+ {
+ address = LLDB_INVALID_ADDRESS;
+ slide = 0;
+ mod_date = 0;
+ file_spec.Clear();
+ ::bzero (&header, sizeof(header));
+ }
+ uuid.Clear();
+ segments.clear();
+ }
+
+ bool
+ operator == (const DYLDImageInfo& rhs) const
+ {
+ return address == rhs.address
+ && slide == rhs.slide
+ && mod_date == rhs.mod_date
+ && file_spec == rhs.file_spec
+ && uuid == rhs.uuid
+ && memcmp(&header, &rhs.header, sizeof(header)) == 0
+ && segments == rhs.segments;
+ }
+
+ bool
+ UUIDValid() const
+ {
+ return uuid.IsValid();
+ }
+
+ const Segment *
+ FindSegment (const lldb_private::ConstString &name) const;
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ typedef std::vector<DYLDImageInfo> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ struct DYLDAllImageInfos
+ {
+ uint32_t version;
+ uint32_t dylib_info_count; // Version >= 1
+ lldb::addr_t dylib_info_addr; // Version >= 1
+ lldb::addr_t notification; // Version >= 1
+ bool processDetachedFromSharedRegion; // Version >= 1
+ bool libSystemInitialized; // Version >= 2
+ lldb::addr_t dyldImageLoadAddress; // Version >= 2
+
+ DYLDAllImageInfos() :
+ version (0),
+ dylib_info_count (0),
+ dylib_info_addr (LLDB_INVALID_ADDRESS),
+ notification (LLDB_INVALID_ADDRESS),
+ processDetachedFromSharedRegion (false),
+ libSystemInitialized (false),
+ dyldImageLoadAddress (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ void
+ Clear()
+ {
+ version = 0;
+ dylib_info_count = 0;
+ dylib_info_addr = LLDB_INVALID_ADDRESS;
+ notification = LLDB_INVALID_ADDRESS;
+ processDetachedFromSharedRegion = false;
+ libSystemInitialized = false;
+ dyldImageLoadAddress = LLDB_INVALID_ADDRESS;
+ }
+
+ bool
+ IsValid() const
+ {
+ return version >= 1 || version <= 6;
+ }
+ };
+
+ void
+ RegisterNotificationCallbacks();
+
+ void
+ UnregisterNotificationCallbacks();
+
+ uint32_t
+ ParseLoadCommands (const lldb_private::DataExtractor& data,
+ struct DYLDImageInfo& dylib_info,
+ lldb_private::FileSpec *lc_id_dylinker);
+
+ bool
+ UpdateImageLoadAddress(lldb_private::Module *module,
+ struct DYLDImageInfo& info);
+
+ bool
+ UnloadImageLoadAddress (lldb_private::Module *module,
+ struct DYLDImageInfo& info);
+
+ bool
+ NeedToLocateDYLD () const;
+
+ bool
+ SetNotificationBreakpoint ();
+
+ bool
+ ReadAllImageInfosStructure ();
+
+ DYLDImageInfo m_dyld; // Info about the curent dyld being used
+ lldb::addr_t m_dyld_all_image_infos_addr;
+ DYLDAllImageInfos m_dyld_all_image_infos;
+ lldb::user_id_t m_break_id;
+ DYLDImageInfo::collection m_dyld_image_infos; // Current shared libraries information
+ mutable lldb_private::Mutex m_mutex;
+ lldb_private::Process::Notifications m_notification_callbacks;
+ std::auto_ptr<lldb_private::ObjCTrampolineHandler> m_objc_trampoline_handler_ap;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoaderMacOSXDYLD);
+};
+
+#endif // liblldb_DynamicLoaderMacOSXDYLD_h_
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.cpp
new file mode 100644
index 0000000..946c8f9
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.cpp
@@ -0,0 +1,72 @@
+//===-- DynamicLoaderMacOSXDYLDLog.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicLoaderMacOSXDYLDLog.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+static Log *
+LogAccessor (bool get, Log *log)
+{
+ static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+ if (get)
+ {
+// // Debug code below for enabling logging by default
+// if (g_log == NULL)
+// {
+// g_log = new Log("/dev/stdout", false);
+// g_log->GetMask().SetAllFlagBits(0xffffffffu);
+// g_log->GetOptions().Set(LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_THREAD_NAME);
+// }
+ }
+ else
+ {
+ if (g_log)
+ delete g_log;
+ g_log = log;
+ }
+
+ return g_log;
+}
+
+Log *
+DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = LogAccessor (true, NULL);
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+DynamicLoaderMacOSXDYLDLog::SetLog (Log *log)
+{
+ LogAccessor (false, log);
+}
+
+
+void
+DynamicLoaderMacOSXDYLDLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log = DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (mask);
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.h
new file mode 100644
index 0000000..9282ba5
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.h
@@ -0,0 +1,34 @@
+//===-- DynamicLoaderMacOSXDYLDLog.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_DynamicLoaderMacOSXDYLDLog_h_
+#define liblldb_DynamicLoaderMacOSXDYLDLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+#include "lldb/lldb-private.h"
+
+// Project includes
+
+class DynamicLoaderMacOSXDYLDLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet (uint32_t mask);
+
+ static void
+ SetLog (lldb_private::Log *log);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_DynamicLoaderMacOSXDYLDLog_h_
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.cpp
new file mode 100644
index 0000000..169dc89
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.cpp
@@ -0,0 +1,328 @@
+//===-- ObjCTrampolineHandler.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjCTrampolineHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "ThreadPlanStepThroughObjCTrampoline.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const ObjCTrampolineHandler::DispatchFunction
+ObjCTrampolineHandler::g_dispatch_functions[] =
+{
+ // NAME STRET SUPER FIXUP TYPE
+ {"objc_msgSend", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_fixup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_fixedup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSend_stret", true, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_stret_fixup", true, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_stret_fixedup", true, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSend_fpret", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_fpret_fixup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_fpret_fixedup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSend_fp2ret", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_fp2ret_fixup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_fp2ret_fixedup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSendSuper", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper_stret", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper2", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper2_fixup", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSendSuper2_fixedup", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSendSuper2_stret", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper2_stret_fixup", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSendSuper2_stret_fixedup", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {NULL}
+};
+
+bool
+ObjCTrampolineHandler::ModuleIsObjCLibrary (const ModuleSP &module_sp)
+{
+ const FileSpec &module_file_spec = module_sp->GetFileSpec();
+ static ConstString ObjCName ("libobjc.A.dylib");
+
+ if (module_file_spec)
+ {
+ if (module_file_spec.GetFilename() == ObjCName)
+ return true;
+ }
+
+ return false;
+}
+
+ObjCTrampolineHandler::ObjCTrampolineHandler (ProcessSP process_sp, ModuleSP objc_module) :
+ m_process_sp (process_sp),
+ m_objc_module_sp (objc_module),
+ m_impl_fn_addr (LLDB_INVALID_ADDRESS),
+ m_impl_stret_fn_addr (LLDB_INVALID_ADDRESS)
+{
+ // Look up the known resolution functions:
+
+ ConstString get_impl_name("class_getMethodImplementation");
+ ConstString get_impl_stret_name("class_getMethodImplementation_stret");
+
+ const Symbol *class_getMethodImplementation = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_name, eSymbolTypeCode);
+ const Symbol *class_getMethodImplementation_stret = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_stret_name, eSymbolTypeCode);
+
+ if (class_getMethodImplementation)
+ m_impl_fn_addr = class_getMethodImplementation->GetValue().GetLoadAddress(m_process_sp.get());
+ if (class_getMethodImplementation_stret)
+ m_impl_stret_fn_addr = class_getMethodImplementation_stret->GetValue().GetLoadAddress(m_process_sp.get());
+
+ // FIXME: Do some kind of logging here.
+ if (m_impl_fn_addr == LLDB_INVALID_ADDRESS || m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ // Look up the addresses for the objc dispatch functions and cache them. For now I'm inspecting the symbol
+ // names dynamically to figure out how to dispatch to them. If it becomes more complicated than this we can
+ // turn the g_dispatch_functions char * array into a template table, and populate the DispatchFunction map
+ // from there.
+
+ for (int i = 0; g_dispatch_functions[i].name != NULL; i++)
+ {
+ ConstString name_const_str(g_dispatch_functions[i].name);
+ const Symbol *msgSend_symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType (name_const_str, eSymbolTypeCode);
+ if (msgSend_symbol)
+ {
+ // FixMe: Make g_dispatch_functions static table of DisptachFunctions, and have the map be address->index.
+ // Problem is we also need to lookup the dispatch function. For now we could have a side table of stret & non-stret
+ // dispatch functions. If that's as complex as it gets, we're fine.
+
+ lldb::addr_t sym_addr = msgSend_symbol->GetValue().GetLoadAddress(m_process_sp.get());
+
+ m_msgSend_map.insert(std::pair<lldb::addr_t, int>(sym_addr, i));
+ }
+ }
+}
+
+ThreadPlanSP
+ObjCTrampolineHandler::GetStepThroughDispatchPlan (Thread &thread, bool stop_others)
+{
+ ThreadPlanSP ret_plan_sp;
+ lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
+
+ MsgsendMap::iterator pos;
+ pos = m_msgSend_map.find (curr_pc);
+ if (pos != m_msgSend_map.end())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ const DispatchFunction *this_dispatch = &g_dispatch_functions[(*pos).second];
+
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+
+ Process *process = thread.CalculateProcess();
+ const ABI *abi = process->GetABI();
+ if (abi == NULL)
+ return ret_plan_sp;
+
+ Target *target = thread.CalculateTarget();
+
+ // FIXME: Since neither the value nor the Clang QualType know their ASTContext,
+ // we have to make sure the type we put in our value list comes from the same ASTContext
+ // the ABI will use to get the argument values. THis is the bottom-most frame's module.
+
+ ClangASTContext *clang_ast_context = target->GetScratchClangASTContext();
+ ValueList argument_values;
+ Value input_value;
+ void *clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
+ input_value.SetValueType (Value::eValueTypeScalar);
+ input_value.SetContext (Value::eContextTypeOpaqueClangQualType, clang_void_ptr_type);
+
+ int obj_index;
+ int sel_index;
+
+ // If this is a struct return dispatch, then the first argument is the
+ // return struct pointer, and the object is the second, and the selector is the third.
+ // Otherwise the object is the first and the selector the second.
+ if (this_dispatch->stret_return)
+ {
+ obj_index = 1;
+ sel_index = 2;
+ argument_values.PushValue(input_value);
+ argument_values.PushValue(input_value);
+ argument_values.PushValue(input_value);
+ }
+ else
+ {
+ obj_index = 0;
+ sel_index = 1;
+ argument_values.PushValue(input_value);
+ argument_values.PushValue(input_value);
+ }
+
+
+ bool success = abi->GetArgumentValues (thread, argument_values);
+ if (!success)
+ return ret_plan_sp;
+
+ // Okay, the first value here is the object, we actually want the class of that object.
+ // For now we're just going with the ISA.
+ // FIXME: This should really be the return value of [object class] to properly handle KVO interposition.
+
+ Value isa_value(*(argument_values.GetValueAtIndex(obj_index)));
+
+ // This is a little cheesy, but since object->isa is the first field,
+ // making the object value a load address value and resolving it will get
+ // the pointer sized data pointed to by that value...
+ ExecutionContext exec_ctx;
+ thread.Calculate (exec_ctx);
+
+ isa_value.SetValueType(Value::eValueTypeLoadAddress);
+ isa_value.ResolveValue(&exec_ctx, clang_ast_context->getASTContext());
+
+ if (this_dispatch->fixedup == DispatchFunction::eFixUpFixed)
+ {
+ // For the FixedUp method the Selector is actually a pointer to a
+ // structure, the second field of which is the selector number.
+ Value *sel_value = argument_values.GetValueAtIndex(sel_index);
+ sel_value->GetScalar() += process->GetAddressByteSize();
+ sel_value->SetValueType(Value::eValueTypeLoadAddress);
+ sel_value->ResolveValue(&exec_ctx, clang_ast_context->getASTContext());
+ }
+ else if (this_dispatch->fixedup == DispatchFunction::eFixUpToFix)
+ {
+ // FIXME: If the method dispatch is not "fixed up" then the selector is actually a
+ // pointer to the string name of the selector. We need to look that up...
+ // For now I'm going to punt on that and just return no plan.
+ if (log)
+ log->Printf ("Punting on stepping into un-fixed-up method dispatch.");
+ return ret_plan_sp;
+ }
+
+ // FIXME: If this is a dispatch to the super-class, we need to get the super-class from
+ // the class, and disaptch to that instead.
+ // But for now I just punt and return no plan.
+ if (this_dispatch->is_super)
+ {
+ if (log)
+ log->Printf ("Punting on stepping into super method dispatch.");
+ return ret_plan_sp;
+ }
+
+ ValueList dispatch_values;
+ dispatch_values.PushValue (isa_value);
+ dispatch_values.PushValue(*(argument_values.GetValueAtIndex(sel_index)));
+
+ if (log)
+ {
+ log->Printf("Resolving method call for class - 0x%llx and selector - 0x%llx",
+ dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong());
+ }
+
+ lldb::addr_t impl_addr = LookupInCache (dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong());
+
+ if (impl_addr == LLDB_INVALID_ADDRESS)
+ {
+
+ Address resolve_address(NULL, this_dispatch->stret_return ? m_impl_stret_fn_addr : m_impl_fn_addr);
+
+ StreamString errors;
+ {
+ // Scope for mutex locker:
+ Mutex::Locker (m_impl_function_mutex);
+ if (!m_impl_function.get())
+ {
+ m_impl_function.reset(new ClangFunction(process->GetTargetTriple().GetCString(),
+ clang_ast_context,
+ clang_void_ptr_type,
+ resolve_address,
+ dispatch_values));
+
+ unsigned num_errors = m_impl_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return ret_plan_sp;
+ }
+
+ errors.Clear();
+ if (!m_impl_function->WriteFunctionWrapper(exec_ctx, errors))
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return ret_plan_sp;
+ }
+ }
+
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this call.
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+ if (!m_impl_function->WriteFunctionArguments (exec_ctx, args_addr, resolve_address, dispatch_values, errors))
+ return ret_plan_sp;
+
+ ret_plan_sp.reset (new ThreadPlanStepThroughObjCTrampoline (thread, this, args_addr,
+ argument_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong(),
+ stop_others));
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Found implementation address in cache: 0x%llx", impl_addr);
+
+ ret_plan_sp.reset (new ThreadPlanRunToAddress (thread, impl_addr, stop_others));
+ }
+ }
+
+ return ret_plan_sp;
+}
+
+void
+ObjCTrampolineHandler::AddToCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ {
+ log->Printf ("Caching: class 0x%llx selector 0x%llx implementation 0x%llx.", class_addr, selector, impl_addr);
+ }
+ m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
+}
+
+lldb::addr_t
+ObjCTrampolineHandler::LookupInCache (lldb::addr_t class_addr, lldb::addr_t selector)
+{
+ MsgImplMap::iterator pos, end = m_impl_cache.end();
+ pos = m_impl_cache.find (ClassAndSel(class_addr, selector));
+ if (pos != end)
+ return (*pos).second;
+ return LLDB_INVALID_ADDRESS;
+}
+
+ClangFunction *
+ObjCTrampolineHandler::GetLookupImplementationWrapperFunction ()
+{
+ return m_impl_function.get();
+}
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.h
new file mode 100644
index 0000000..bc06d26
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.h
@@ -0,0 +1,133 @@
+//===-- ObjCTrampolineHandler.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_ObjCTrampolineHandler_h_
+#define lldb_ObjCTrampolineHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "lldb.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Mutex.h"
+
+
+namespace lldb_private
+{
+using namespace lldb;
+
+class ObjCTrampolineHandler {
+public:
+
+ ObjCTrampolineHandler (ProcessSP process_sp, ModuleSP objc_module_sp);
+
+ ~ObjCTrampolineHandler() {}
+
+ static bool ModuleIsObjCLibrary (const ModuleSP &module_sp);
+
+ ThreadPlanSP
+ GetStepThroughDispatchPlan (Thread &thread, bool stop_others);
+
+ void
+ AddToCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr);
+
+ lldb::addr_t
+ LookupInCache (lldb::addr_t class_addr, lldb::addr_t sel);
+
+ ClangFunction *
+ GetLookupImplementationWrapperFunction ();
+
+
+ struct DispatchFunction {
+ public:
+ typedef enum
+ {
+ eFixUpNone,
+ eFixUpFixed,
+ eFixUpToFix
+ } FixUpState;
+
+ const char *name;
+ bool stret_return;
+ bool is_super;
+ FixUpState fixedup;
+ };
+
+private:
+ static const DispatchFunction g_dispatch_functions[];
+
+ typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch fn address to the index in g_dispatch_functions
+ MsgsendMap m_msgSend_map;
+ ProcessSP m_process_sp;
+ ModuleSP m_objc_module_sp;
+ lldb::addr_t get_impl_addr;
+ std::auto_ptr<ClangFunction> m_impl_function;
+ Mutex m_impl_function_mutex;
+ lldb::addr_t m_impl_fn_addr;
+ lldb::addr_t m_impl_stret_fn_addr;
+
+
+ // We keep a map of <Class,Selector>->Implementation so we don't have to call the resolver
+ // function over and over.
+
+ // FIXME: We need to watch for the loading of Protocols, and flush the cache for any
+ // class that we see so changed.
+
+ struct ClassAndSel
+ {
+ ClassAndSel()
+ {
+ sel_addr = LLDB_INVALID_ADDRESS;
+ class_addr = LLDB_INVALID_ADDRESS;
+ }
+ ClassAndSel (lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) :
+ class_addr (in_class_addr),
+ sel_addr(in_sel_addr)
+ {
+ }
+ bool operator== (const ClassAndSel &rhs)
+ {
+ if (class_addr == rhs.class_addr
+ && sel_addr == rhs.sel_addr)
+ return true;
+ else
+ return false;
+ }
+
+ bool operator< (const ClassAndSel &rhs) const
+ {
+ if (class_addr < rhs.class_addr)
+ return true;
+ else if (class_addr > rhs.class_addr)
+ return false;
+ else
+ {
+ if (sel_addr < rhs.sel_addr)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ lldb::addr_t class_addr;
+ lldb::addr_t sel_addr;
+ };
+
+ typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap;
+ MsgImplMap m_impl_cache;
+
+};
+
+}; // using namespace lldb_private
+
+#endif // lldb_ObjCTrampolineHandler_h_
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp
new file mode 100644
index 0000000..a0cb0a8
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp
@@ -0,0 +1,151 @@
+//===-- ThreadPlanStepThroughObjCTrampoline.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 "ThreadPlanStepThroughObjCTrampoline.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepThroughObjCTrampoline constructor
+//----------------------------------------------------------------------
+ThreadPlanStepThroughObjCTrampoline::ThreadPlanStepThroughObjCTrampoline(
+ Thread &thread,
+ ObjCTrampolineHandler *trampoline_handler,
+ lldb::addr_t args_addr,
+ lldb::addr_t object_ptr,
+ lldb::addr_t class_ptr,
+ lldb::addr_t sel_ptr,
+ bool stop_others) :
+ ThreadPlan ("MacOSX Step through ObjC Trampoline", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_objc_trampoline_handler (trampoline_handler),
+ m_impl_function (trampoline_handler->GetLookupImplementationWrapperFunction()),
+ m_args_addr (args_addr),
+ m_object_ptr (object_ptr),
+ m_class_ptr (class_ptr),
+ m_sel_ptr (sel_ptr),
+ m_stop_others (stop_others)
+{
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ThreadPlanStepThroughObjCTrampoline::~ThreadPlanStepThroughObjCTrampoline()
+{
+}
+
+void
+ThreadPlanStepThroughObjCTrampoline::DidPush ()
+{
+ StreamString errors;
+ ExecutionContext exc_context;
+ m_thread.Calculate(exc_context);
+ m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_context, m_args_addr, errors, m_stop_others));
+ m_func_sp->SetPrivate(true);
+ m_thread.QueueThreadPlan (m_func_sp, false);
+}
+
+void
+ThreadPlanStepThroughObjCTrampoline::GetDescription (Stream *s,
+ lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf("Step through ObjC trampoline");
+ else
+ {
+ s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx class: 0x%llx selector: 0x%llx",
+ m_object_ptr, m_class_ptr, m_sel_ptr);
+ }
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::PlanExplainsStop ()
+{
+ // This plan should actually never stop when it is on the top of the plan
+ // stack, since it does all it's running in client plans.
+ return false;
+}
+
+lldb::StateType
+ThreadPlanStepThroughObjCTrampoline::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr)
+{
+ if (m_func_sp.get() == NULL || m_thread.IsThreadPlanDone(m_func_sp.get()))
+ {
+ m_func_sp.reset();
+ if (!m_run_to_sp)
+ {
+ Value target_addr_value;
+ ExecutionContext exc_context;
+ m_thread.Calculate(exc_context);
+ m_impl_function->FetchFunctionResults (exc_context, m_args_addr, target_addr_value);
+ m_impl_function->DeallocateFunctionResults(exc_context, m_args_addr);
+ lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
+ Address target_address(NULL, target_addr);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf("Running to ObjC method implementation: 0x%llx", target_addr);
+
+ m_objc_trampoline_handler->AddToCache (m_class_ptr, m_sel_ptr, target_addr);
+
+ // Extract the target address from the value:
+
+ m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_address, m_stop_others));
+ m_thread.QueueThreadPlan(m_run_to_sp, false);
+ m_run_to_sp->SetPrivate(true);
+ return false;
+ }
+ else if (m_thread.IsThreadPlanDone(m_run_to_sp.get()))
+ {
+ SetPlanComplete();
+ return true;
+ }
+ }
+ return false;
+}
+
+// The base class MischiefManaged does some cleanup - so you have to call it
+// in your MischiefManaged derived class.
+bool
+ThreadPlanStepThroughObjCTrampoline::MischiefManaged ()
+{
+ if (IsPlanComplete())
+ return true;
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::WillStop()
+{
+ return true;
+}
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.h
new file mode 100644
index 0000000..8033718
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.h
@@ -0,0 +1,94 @@
+//===-- ThreadPlanStepThroughObjCTrampoline.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_ThreadPlanStepThroughObjCTrampoline_h_
+#define lldb_ThreadPlanStepThroughObjCTrampoline_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb-types.h"
+#include "lldb-enumerations.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "ObjCTrampolineHandler.h"
+
+namespace lldb_private
+{
+
+class ThreadPlanStepThroughObjCTrampoline : public ThreadPlan
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ThreadPlanStepThroughObjCTrampoline(Thread &thread,
+ ObjCTrampolineHandler *trampoline_handler,
+ lldb::addr_t args_addr,
+ lldb::addr_t object_ptr,
+ lldb::addr_t class_ptr,
+ lldb::addr_t sel_ptr,
+ bool stop_others);
+
+ virtual ~ThreadPlanStepThroughObjCTrampoline();
+
+ virtual void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ PlanExplainsStop ();
+
+
+ virtual lldb::StateType
+ RunState ();
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ // The base class MischiefManaged does some cleanup - so you have to call it
+ // in your MischiefManaged derived class.
+ virtual bool
+ MischiefManaged ();
+
+ virtual void
+ DidPush();
+
+ virtual bool
+ WillStop();
+
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ThreadPlanStepThroughObjCTrampoline can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For ThreadPlanStepThroughObjCTrampoline only
+ //------------------------------------------------------------------
+ ThreadPlanSP m_func_sp; // This is the function call plan. We fill it at start, then set it
+ // to NULL when this plan is done. That way we know to go to:
+ lldb::addr_t m_args_addr; // Stores the address for our step through function result structure.
+ ThreadPlanSP m_run_to_sp; // The plan that runs to the target.
+ bool m_stop_others;
+ ObjCTrampolineHandler *m_objc_trampoline_handler;
+ ClangFunction *m_impl_function; // This is a pointer to a impl function that
+ // is owned by the client that pushes this plan.
+ lldb::addr_t m_object_ptr;
+ lldb::addr_t m_class_ptr;
+ lldb::addr_t m_sel_ptr;
+};
+
+}; // namespace lldb_private
+#endif // lldb_ThreadPlanStepThroughObjCTrampoline_h_
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
new file mode 100644
index 0000000..c2fb2a5
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -0,0 +1,428 @@
+//===-- ObjectContainerBSDArchive.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerBSDArchive.h"
+
+#include <ar.h>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+ObjectContainerBSDArchive::Object::Object() :
+ ar_name(),
+ ar_date(0),
+ ar_uid(0),
+ ar_gid(0),
+ ar_mode(0),
+ ar_size(0),
+ ar_file_offset(0),
+ ar_file_size(0)
+{
+}
+
+void
+ObjectContainerBSDArchive::Object::Clear()
+{
+ ar_name.Clear();
+ ar_date = 0;
+ ar_uid = 0;
+ ar_gid = 0;
+ ar_mode = 0;
+ ar_size = 0;
+ ar_file_offset = 0;
+ ar_file_size = 0;
+}
+
+uint32_t
+ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, uint32_t offset)
+{
+ size_t ar_name_len = 0;
+ std::string str;
+ char *err;
+ str.assign ((const char *)data.GetData(&offset, 16), 16);
+ if (str.find(AR_EFMT1) == 0)
+ {
+ // If the name is longer than 16 bytes, or contains an embedded space
+ // then it will use this format where the length of the name is
+ // here and the name characters are after this header.
+ ar_name_len = strtoul(str.c_str() + 3, &err, 10);
+ }
+ else
+ {
+ // Strip off any spaces (if the object file name contains spaces it
+ // will use the extended format above).
+ str.erase (str.find(' '));
+ ar_name.SetCString(str.c_str());
+ }
+
+ str.assign ((const char *)data.GetData(&offset, 12), 12);
+ ar_date = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 6), 6);
+ ar_uid = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 6), 6);
+ ar_gid = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 8), 8);
+ ar_mode = strtoul(str.c_str(), &err, 8);
+
+ str.assign ((const char *)data.GetData(&offset, 10), 10);
+ ar_size = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 2), 2);
+ if (str == ARFMAG)
+ {
+ if (ar_name_len > 0)
+ {
+ str.assign ((const char *)data.GetData(&offset, ar_name_len), ar_name_len);
+ ar_name.SetCString (str.c_str());
+ }
+ ar_file_offset = offset;
+ ar_file_size = ar_size - ar_name_len;
+ return offset;
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+ObjectContainerBSDArchive::Archive::Archive
+(
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &time
+) :
+ m_arch (arch),
+ m_time (time),
+ m_objects()
+{
+}
+
+ObjectContainerBSDArchive::Archive::~Archive ()
+{
+}
+
+size_t
+ObjectContainerBSDArchive::Archive::ParseObjects (DataExtractor &data)
+{
+ std::string str;
+ uint32_t offset = 0;
+ str.assign((const char *)data.GetData(&offset, SARMAG), SARMAG);
+ if (str == ARMAG)
+ {
+ Object obj;
+ do
+ {
+ offset = obj.Extract (data, offset);
+ if (offset == LLDB_INVALID_INDEX32)
+ break;
+ uint32_t obj_idx = m_objects.size();
+ m_objects.push_back(obj);
+ // Insert all of the C strings out of order for now...
+ m_object_name_to_index_map.Append (obj.ar_name.GetCString(), obj_idx);
+ offset += obj.ar_file_size;
+ obj.Clear();
+ } while (data.ValidOffset(offset));
+
+ // Now sort all of the object name pointers
+ m_object_name_to_index_map.Sort ();
+ }
+ return m_objects.size();
+}
+
+ObjectContainerBSDArchive::Object *
+ObjectContainerBSDArchive::Archive::FindObject (const ConstString &object_name)
+{
+ const UniqueCStringMap<uint32_t>::Entry *match = m_object_name_to_index_map.FindFirstValueForName (object_name.GetCString());
+ if (match)
+ return &m_objects[match->value];
+ return NULL;
+}
+
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, const ArchSpec &arch, const TimeValue &time)
+{
+ Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+ shared_ptr archive_sp;
+ Archive::Map &archive_map = Archive::GetArchiveCache ();
+ Archive::Map::iterator pos;
+ for (pos = archive_map.find (file); pos != archive_map.end() && pos->first == file; ++pos)
+ {
+ if (pos->second->GetArchitecture() == arch &&
+ pos->second->GetModificationTime() == time)
+ {
+ archive_sp = pos->second;
+ }
+ }
+ return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile
+(
+ const FileSpec &file,
+ const ArchSpec &arch,
+ const TimeValue &time,
+ DataExtractor &data
+)
+{
+ shared_ptr archive_sp(new Archive (arch, time));
+ if (archive_sp)
+ {
+ if (archive_sp->ParseObjects (data) > 0)
+ {
+ Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+ Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp));
+ }
+ else
+ {
+ archive_sp.reset();
+ }
+ }
+ return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::Map &
+ObjectContainerBSDArchive::Archive::GetArchiveCache ()
+{
+ static Archive::Map g_archive_map;
+ return g_archive_map;
+}
+
+Mutex &
+ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex ()
+{
+ static Mutex g_archive_map_mutex (Mutex::eMutexTypeRecursive);
+ return g_archive_map_mutex;
+}
+
+
+void
+ObjectContainerBSDArchive::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+ObjectContainerBSDArchive::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectContainerBSDArchive::GetPluginNameStatic()
+{
+ return "object-container.bsd-archive";
+}
+
+const char *
+ObjectContainerBSDArchive::GetPluginDescriptionStatic()
+{
+ return "BSD Archive object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerBSDArchive::CreateInstance
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const FileSpec *file,
+ addr_t offset,
+ addr_t length)
+{
+ if (file)
+ {
+ std::string object;
+
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file, module->GetArchitecture(), module->GetModificationTime()));
+
+ if (archive_sp)
+ {
+ // We already have this archive in our cache, use it
+ std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length));
+ if (container_ap.get())
+ {
+ container_ap->SetArchive (archive_sp);
+ return container_ap.release();
+ }
+ }
+
+ if (dataSP)
+ {
+ if (ObjectContainerBSDArchive::MagicBytesMatch(dataSP))
+ {
+ // Read everything since we need that in order to index all the
+ // objects in the archive
+ dataSP = file->ReadFileContents(offset, length);
+
+ std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length));
+ if (container_ap->ParseHeader())
+ return container_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+bool
+ObjectContainerBSDArchive::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ uint32_t offset = 0;
+ const char* armag = (const char* )data.PeekData (offset, sizeof(ar_hdr));
+ if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0)
+ {
+ armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
+ if (strncmp(armag, ARFMAG, 2) == 0)
+ return true;
+ }
+ return false;
+}
+
+ObjectContainerBSDArchive::ObjectContainerBSDArchive
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t size
+) :
+ ObjectContainer (module, file, offset, size, dataSP),
+ m_archive_sp ()
+{
+}
+void
+ObjectContainerBSDArchive::SetArchive (Archive::shared_ptr &archive_sp)
+{
+ m_archive_sp = archive_sp;
+}
+
+
+
+ObjectContainerBSDArchive::~ObjectContainerBSDArchive()
+{
+}
+
+bool
+ObjectContainerBSDArchive::ParseHeader ()
+{
+ if (m_archive_sp.get() == NULL)
+ {
+ if (m_data.GetByteSize() > 0)
+ {
+ m_archive_sp = Archive::ParseAndCacheArchiveForFile (m_file,
+ m_module->GetArchitecture(),
+ m_module->GetModificationTime(),
+ m_data);
+ // The archive might be huge, so clear "m_data" to free up the
+ // memory since it will contain the entire file (possibly more than
+ // one architecture slice). We already have an index of all objects
+ // in the file, so we will be ready to serve up those objects.
+ m_data.Clear();
+ }
+ }
+ return m_archive_sp.get() != NULL;
+}
+
+void
+ObjectContainerBSDArchive::Dump (Stream *s) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ const size_t num_archs = GetNumArchitectures();
+ const size_t num_objects = GetNumObjects();
+ s->Printf("ObjectContainerBSDArchive, num_archs = %u, num_objects = %u", num_archs, num_objects);
+ uint32_t i;
+ ArchSpec arch;
+ s->IndentMore();
+ for (i=0; i<num_archs; i++)
+ {
+ s->Indent();
+ GetArchitectureAtIndex(i, arch);
+ s->Printf("arch[%u] = %s\n", arch.AsCString());
+ }
+ for (i=0; i<num_objects; i++)
+ {
+ s->Indent();
+ s->Printf("object[%u] = %s\n", GetObjectNameAtIndex (i));
+ }
+ s->IndentLess();
+ s->EOL();
+}
+
+ObjectFile *
+ObjectContainerBSDArchive::GetObjectFile (const FileSpec *file)
+{
+ if (m_module->GetObjectName() && m_archive_sp)
+ {
+ Object *object = m_archive_sp->FindObject (m_module->GetObjectName());
+ if (object)
+ return ObjectFile::FindPlugin (m_module, file, m_offset + object->ar_file_offset, object->ar_file_size);
+ }
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectContainerBSDArchive::GetPluginName()
+{
+ return "object-container.bsd-archive";
+}
+
+const char *
+ObjectContainerBSDArchive::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerBSDArchive::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectContainerBSDArchive::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectContainerBSDArchive::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectContainerBSDArchive::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
new file mode 100644
index 0000000..88aba01
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -0,0 +1,183 @@
+//===-- ObjectContainerBSDArchive.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_ObjectContainerBSDArchive_h_
+#define liblldb_ObjectContainerBSDArchive_h_
+
+#include "lldb/Symbol/ObjectContainer.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Host/TimeValue.h"
+
+class ObjectContainerBSDArchive :
+ public lldb_private::ObjectContainer
+{
+public:
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectContainer *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectContainerBSDArchive (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectContainerBSDArchive();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual void
+ Dump (lldb_private::Stream *s) const;
+
+ virtual lldb_private::ObjectFile *
+ GetObjectFile (const lldb_private::FileSpec *file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+protected:
+
+ struct Object
+ {
+ Object();
+
+ void
+ Clear();
+
+ uint32_t
+ Extract (const lldb_private::DataExtractor& data, uint32_t offset);
+
+ lldb_private::ConstString ar_name; // name
+ uint32_t ar_date; // modification time
+ uint16_t ar_uid; // user id
+ uint16_t ar_gid; // group id
+ uint16_t ar_mode; // octal file permissions
+ uint32_t ar_size; // size in bytes
+ uint32_t ar_file_offset; // file offset in bytes from the beginning of the file of the object data
+ uint32_t ar_file_size; // length of the object data
+
+ typedef std::vector<Object> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ class Archive
+ {
+ public:
+ typedef lldb::SharedPtr<Archive>::Type shared_ptr;
+ typedef std::multimap<lldb_private::FileSpec, shared_ptr> Map;
+
+ static Map &
+ GetArchiveCache ();
+
+ static lldb_private::Mutex &
+ GetArchiveCacheMutex ();
+
+ static Archive::shared_ptr
+ FindCachedArchive (const lldb_private::FileSpec &file,
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time);
+
+ static Archive::shared_ptr
+ ParseAndCacheArchiveForFile (const lldb_private::FileSpec &file,
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb_private::DataExtractor &data);
+
+ Archive (const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time);
+
+ ~Archive ();
+
+ size_t
+ ParseObjects (lldb_private::DataExtractor &data);
+
+ Object *
+ FindObject (const lldb_private::ConstString &object_name);
+
+ const lldb_private::TimeValue &
+ GetModificationTime()
+ {
+ return m_time;
+ }
+
+ const lldb_private::ArchSpec &
+ GetArchitecture ()
+ {
+ return m_arch;
+ }
+
+ protected:
+
+ //----------------------------------------------------------------------
+ // Member Variables
+ //----------------------------------------------------------------------
+ lldb_private::ArchSpec m_arch;
+ lldb_private::TimeValue m_time;
+ Object::collection m_objects;
+ lldb_private::UniqueCStringMap<uint32_t> m_object_name_to_index_map;
+ };
+
+ void
+ SetArchive (Archive::shared_ptr &archive_sp);
+
+ Archive::shared_ptr m_archive_sp;
+};
+
+#endif // liblldb_ObjectContainerBSDArchive_h_
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
new file mode 100644
index 0000000..015e498
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
@@ -0,0 +1,259 @@
+//===-- ObjectContainerUniversalMachO.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerUniversalMachO.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+void
+ObjectContainerUniversalMachO::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+ObjectContainerUniversalMachO::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectContainerUniversalMachO::GetPluginNameStatic()
+{
+ return "object-container.mach-o";
+}
+
+const char *
+ObjectContainerUniversalMachO::GetPluginDescriptionStatic()
+{
+ return "Universal mach-o object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerUniversalMachO::CreateInstance
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const FileSpec *file,
+ addr_t offset,
+ addr_t length
+)
+{
+ if (ObjectContainerUniversalMachO::MagicBytesMatch(dataSP))
+ {
+ std::auto_ptr<ObjectContainerUniversalMachO> container_ap(new ObjectContainerUniversalMachO (module, dataSP, file, offset, length));
+ if (container_ap->ParseHeader())
+ {
+ return container_ap.release();
+ }
+ }
+ return NULL;
+}
+
+
+
+bool
+ObjectContainerUniversalMachO::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ uint32_t offset = 0;
+ uint32_t magic = data.GetU32(&offset);
+ return magic == FAT_MAGIC || magic == FAT_CIGAM;
+}
+
+ObjectContainerUniversalMachO::ObjectContainerUniversalMachO
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const FileSpec *file,
+ addr_t offset,
+ addr_t length
+) :
+ ObjectContainer (module, file, offset, length, dataSP),
+ m_header(),
+ m_fat_archs()
+{
+ memset(&m_header, 0, sizeof(m_header));
+}
+
+
+ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO()
+{
+}
+
+bool
+ObjectContainerUniversalMachO::ParseHeader ()
+{
+ // Store the file offset for this universal file as we could have a universal .o file
+ // in a BSD archive, or be contained in another kind of object.
+ uint32_t offset = 0;
+ // Universal mach-o files always have their headers in big endian.
+ m_data.SetByteOrder (eByteOrderBig);
+ m_header.magic = m_data.GetU32(&offset);
+
+ if (m_header.magic == FAT_MAGIC)
+ {
+ m_data.SetAddressByteSize(4);
+
+ m_header.nfat_arch = m_data.GetU32(&offset);
+
+ const size_t nfat_arch_size = sizeof(fat_arch_t) * m_header.nfat_arch;
+ // See if the current data we have is enough for all of the fat headers?
+ if (!m_data.ValidOffsetForDataOfSize(offset, nfat_arch_size))
+ {
+ // The fat headers are larger than the number of bytes we have been
+ // given when this class was constructed. We will read the exact number
+ // of bytes that we need.
+ DataBufferSP data_sp(m_file.ReadFileContents(m_offset, nfat_arch_size + sizeof(fat_header_t)));
+ m_data.SetData (data_sp);
+ }
+
+ // Now we should have enough data for all of the fat headers, so lets index
+ // them so we know how many architectures that this univeral binary contains.
+ uint32_t arch_idx = 0;
+ for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
+ {
+ if (m_data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch_t)))
+ {
+ fat_arch_t arch;
+ if (m_data.GetU32(&offset, &arch, sizeof(fat_arch_t)/sizeof(uint32_t)))
+ {
+ m_fat_archs.push_back(arch);
+ }
+ }
+ }
+ // Now that we have indexed the universal headers, we no longer need any cached data.
+ m_data.Clear();
+
+ return true;
+ }
+ else
+ {
+ memset(&m_header, 0, sizeof(m_header));
+ }
+
+ return false;
+}
+
+void
+ObjectContainerUniversalMachO::Dump (Stream *s) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ const size_t num_archs = GetNumArchitectures();
+ const size_t num_objects = GetNumObjects();
+ s->Printf("ObjectContainerUniversalMachO, num_archs = %u, num_objects = %u", num_archs, num_objects);
+ uint32_t i;
+ ArchSpec arch;
+ s->IndentMore();
+ for (i=0; i<num_archs; i++)
+ {
+ s->Indent();
+ GetArchitectureAtIndex(i, arch);
+ s->Printf("arch[%u] = %s\n", arch.AsCString());
+ }
+ for (i=0; i<num_objects; i++)
+ {
+ s->Indent();
+ s->Printf("object[%u] = %s\n", GetObjectNameAtIndex (i));
+ }
+ s->IndentLess();
+ s->EOL();
+}
+
+size_t
+ObjectContainerUniversalMachO::GetNumArchitectures () const
+{
+ return m_header.nfat_arch;
+}
+
+bool
+ObjectContainerUniversalMachO::GetArchitectureAtIndex (uint32_t idx, ArchSpec& arch) const
+{
+ if (idx < m_header.nfat_arch)
+ {
+ arch.SetArch(m_fat_archs[idx].cputype, m_fat_archs[idx].cpusubtype);
+ return true;
+ }
+ return false;
+}
+
+ObjectFile *
+ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file)
+{
+ uint32_t arch_idx = 0;
+ const ArchSpec arch = m_module->GetArchitecture();
+ ArchSpec curr_arch;
+ for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
+ {
+ if (GetArchitectureAtIndex (arch_idx, curr_arch))
+ {
+ if (arch == curr_arch)
+ {
+ return ObjectFile::FindPlugin (m_module, file, m_offset + m_fat_archs[arch_idx].offset, m_fat_archs[arch_idx].size);
+ }
+ }
+ }
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectContainerUniversalMachO::GetPluginName()
+{
+ return "ObjectContainerUniversalMachO";
+}
+
+const char *
+ObjectContainerUniversalMachO::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerUniversalMachO::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectContainerUniversalMachO::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectContainerUniversalMachO::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectContainerUniversalMachO::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
new file mode 100644
index 0000000..8a7f975
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
@@ -0,0 +1,103 @@
+//===-- ObjectContainerUniversalMachO.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_ObjectContainerUniversalMachO_h_
+#define liblldb_ObjectContainerUniversalMachO_h_
+
+#include <mach-o/fat.h>
+
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Core/FileSpec.h"
+
+class ObjectContainerUniversalMachO :
+ public lldb_private::ObjectContainer
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectContainer *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectContainerUniversalMachO (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectContainerUniversalMachO();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual void
+ Dump (lldb_private::Stream *s) const;
+
+ virtual size_t
+ GetNumArchitectures () const;
+
+ virtual bool
+ GetArchitectureAtIndex (uint32_t cpu_idx, lldb_private::ArchSpec& arch) const;
+
+ virtual lldb_private::ObjectFile *
+ GetObjectFile (const lldb_private::FileSpec *file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+protected:
+ typedef struct fat_header fat_header_t;
+ typedef struct fat_arch fat_arch_t;
+ fat_header_t m_header;
+ std::vector<fat_arch_t> m_fat_archs;
+};
+
+#endif // liblldb_ObjectContainerUniversalMachO_h_
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
new file mode 100644
index 0000000..b34dd3d
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -0,0 +1,929 @@
+//===-- ObjectFileELF.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectFileELF.h"
+
+#include <mach/machine.h>
+#include <assert.h>
+
+#include <algorithm>
+
+#include <stdint.h>
+#include "elf.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#define CASE_AND_STREAM(s, def, width) case def: s->Printf("%-*s", width, #def); break;
+
+static uint32_t ELFMachineToMachCPU(Elf32_Half machine);
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+
+#include <mach-o/nlist.h>
+#include <mach-o/stab.h>
+
+
+void
+ObjectFileELF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+ObjectFileELF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectFileELF::GetPluginNameStatic()
+{
+ return "object-file.elf32";
+}
+
+const char *
+ObjectFileELF::GetPluginDescriptionStatic()
+{
+ return "ELF object file reader (32-bit).";
+}
+
+
+ObjectFile *
+ObjectFileELF::CreateInstance (Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length)
+{
+ if (ObjectFileELF::MagicBytesMatch(dataSP))
+ {
+ std::auto_ptr<ObjectFile> objfile_ap(new ObjectFileELF (module, dataSP, file, offset, length));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
+}
+
+bool
+ObjectFileELF::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ const uint8_t* magic = data.PeekData(0, 4);
+ if (magic != NULL)
+ {
+ return magic[EI_MAG0] == 0x7f
+ && magic[EI_MAG1] == 'E'
+ && magic[EI_MAG2] == 'L'
+ && magic[EI_MAG3] == 'F';
+ }
+ return false;
+}
+
+
+ObjectFileELF::ObjectFileELF(Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length) :
+ ObjectFile (module, file, offset, length, dataSP),
+ m_header(),
+ m_program_headers(),
+ m_section_headers(),
+ m_sections_ap(),
+ m_symtab_ap(),
+ m_shstr_data()
+{
+ if (file)
+ m_file = *file;
+ ::bzero (&m_header, sizeof(m_header));
+}
+
+
+ObjectFileELF::~ObjectFileELF()
+{
+}
+
+ByteOrder
+ObjectFileELF::GetByteOrder () const
+{
+ if (m_header.e_ident[EI_DATA] == ELFDATA2MSB)
+ return eByteOrderBig;
+ if (m_header.e_ident[EI_DATA] == ELFDATA2LSB)
+ return eByteOrderLittle;
+ return eByteOrderInvalid;
+}
+
+size_t
+ObjectFileELF::GetAddressByteSize () const
+{
+ return m_data.GetAddressByteSize();
+}
+
+bool
+ObjectFileELF::ParseHeader ()
+{
+ m_data.SetAddressByteSize(4);
+ uint32_t offset = GetOffset();
+ if (m_data.GetU8(&offset, m_header.e_ident, EI_NIDENT) == NULL)
+ return false;
+
+ m_data.SetByteOrder(GetByteOrder());
+
+ // Read e_type and e_machine
+ if (m_data.GetU16(&offset, &m_header.e_type, 2) == NULL)
+ return false;
+
+ // read e_version, e_entry, e_phoff, e_shoff, e_flags
+ if (m_data.GetU32(&offset, &m_header.e_version, 5) == NULL)
+ return false;
+
+ // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx
+ if (m_data.GetU16(&offset, &m_header.e_ehsize, 6) == NULL)
+ return false;
+
+ return true;
+}
+
+bool
+ObjectFileELF::GetUUID (UUID* uuid)
+{
+ return false;
+}
+
+uint32_t
+ObjectFileELF::GetDependentModules(FileSpecList& files)
+{
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// ParseProgramHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseProgramHeaders()
+{
+ // We have already parsed the program headers
+ if (!m_program_headers.empty())
+ return m_program_headers.size();
+
+ uint32_t offset = 0;
+ if (m_header.e_phnum > 0)
+ {
+ m_program_headers.resize(m_header.e_phnum);
+
+ if (m_program_headers.size() != m_header.e_phnum)
+ return 0;
+
+ const size_t byte_size = m_header.e_phnum * m_header.e_phentsize;
+ DataBufferSP buffer_sp(m_file.ReadFileContents(m_offset + m_header.e_phoff, byte_size));
+
+ if (buffer_sp.get() == NULL || buffer_sp->GetByteSize() != byte_size)
+ return 0;
+
+ DataExtractor data(buffer_sp, m_data.GetByteOrder(), m_data.GetAddressByteSize());
+
+ uint32_t idx;
+ for (idx = 0; idx < m_header.e_phnum; ++idx)
+ {
+ if (data.GetU32(&offset, &m_program_headers[idx].p_type, 8) == NULL)
+ return 0;
+ }
+ if (idx < m_program_headers.size())
+ m_program_headers.resize(idx);
+ }
+
+ return m_program_headers.size();
+}
+
+
+//----------------------------------------------------------------------
+// ParseSectionHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseSectionHeaders()
+{
+ // We have already parsed the section headers
+ if (!m_section_headers.empty())
+ return m_section_headers.size();
+
+ if (m_header.e_shnum > 0)
+ {
+ uint32_t offset = 0;
+
+ m_section_headers.resize(m_header.e_shnum);
+
+ if (m_section_headers.size() != m_header.e_shnum)
+ return 0;
+
+ const size_t byte_size = m_header.e_shnum * m_header.e_shentsize;
+ DataBufferSP buffer_sp(m_file.ReadFileContents(m_offset + m_header.e_shoff, byte_size));
+
+ if (buffer_sp.get() == NULL || buffer_sp->GetByteSize() != byte_size)
+ return 0;
+
+ DataExtractor data(buffer_sp, m_data.GetByteOrder(), m_data.GetAddressByteSize());
+
+ uint32_t idx;
+ for (idx = 0; idx < m_header.e_shnum; ++idx)
+ {
+ if (data.GetU32(&offset, &m_section_headers[idx].sh_name, 10) == NULL)
+ break;
+ }
+ if (idx < m_section_headers.size())
+ m_section_headers.resize(idx);
+ }
+
+ return m_section_headers.size();
+}
+
+size_t
+ObjectFileELF::GetSectionHeaderStringTable()
+{
+ if (m_shstr_data.GetByteSize() == 0)
+ {
+ if (m_header.e_shstrndx && m_header.e_shstrndx < m_section_headers.size())
+ {
+ const size_t byte_size = m_section_headers[m_header.e_shstrndx].sh_size;
+ DataBufferSP buffer_sp(m_file.ReadFileContents(m_offset + m_section_headers[m_header.e_shstrndx].sh_offset, byte_size));
+
+ if (buffer_sp.get() == NULL || buffer_sp->GetByteSize() != byte_size)
+ return 0;
+
+ m_shstr_data.SetData(buffer_sp);
+ }
+ }
+ return m_shstr_data.GetByteSize();
+}
+
+uint32_t
+ObjectFileELF::GetSectionIndexByName(const char *name)
+{
+ if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+ {
+ uint32_t offset = 1; // Skip leading NULL string at offset 0;
+ while (m_shstr_data.ValidOffset(offset))
+ {
+ uint32_t sh_name = offset; // Save offset in case we find a match
+ const char* sectionHeaderName = m_shstr_data.GetCStr(&offset);
+ if (sectionHeaderName)
+ {
+ if (strcmp(name, sectionHeaderName) == 0)
+ {
+ SectionHeaderCollIter pos;
+ for (pos = m_section_headers.begin(); pos != m_section_headers.end(); ++pos)
+ {
+ if ( (*pos).sh_name == sh_name )
+ {
+ // section indexes are 1 based
+ return std::distance(m_section_headers.begin(), pos) + 1;
+ }
+ }
+ return UINT32_MAX;
+ }
+ }
+ else
+ {
+ return UINT32_MAX;
+ }
+ }
+ }
+
+ return UINT32_MAX;
+}
+
+SectionList *
+ObjectFileELF::GetSectionList()
+{
+ if (m_sections_ap.get() == NULL)
+ {
+ m_sections_ap.reset(new SectionList());
+ if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+ {
+ uint32_t sh_idx = 0;
+ const size_t num_sections = m_section_headers.size();
+ for (sh_idx = 0; sh_idx < num_sections; ++sh_idx)
+ {
+ ConstString section_name(m_shstr_data.PeekCStr(m_section_headers[sh_idx].sh_name));
+ uint64_t section_file_size = m_section_headers[sh_idx].sh_type == SHT_NOBITS ? 0 : m_section_headers[sh_idx].sh_size;
+ SectionSP section_sp(new Section(NULL, // Parent section
+ GetModule(), // Module to which this section belongs
+ sh_idx + 1, // Section ID is the 1 based
+ section_name, // Name of this section
+ eSectionTypeOther, // TODO: fill this in appropriately for ELF...
+ m_section_headers[sh_idx].sh_addr, // File VM address
+ m_section_headers[sh_idx].sh_size, // VM size in bytes of this section
+ m_section_headers[sh_idx].sh_offset, // Offset to the data for this section in the file
+ section_file_size, // Size in bytes of this section as found in the the file
+ m_section_headers[sh_idx].sh_flags)); // Flags for this section
+ if (section_sp.get())
+ m_sections_ap->AddSection(section_sp);
+
+ }
+ }
+ }
+ return m_sections_ap.get();
+}
+
+static void
+ParseSymbols (Symtab *symtab, SectionList *section_list, const Elf32_Shdr &symtab_shdr, const DataExtractor& symtab_data, const DataExtractor& strtab_data)
+{
+ assert (sizeof(Elf32_Sym) == symtab_shdr.sh_entsize);
+ const uint32_t num_symbols = symtab_data.GetByteSize() / sizeof(Elf32_Sym);
+ uint32_t offset = 0;
+ Elf32_Sym symbol;
+ uint32_t i;
+ static ConstString text_section_name(".text");
+ static ConstString init_section_name(".init");
+ static ConstString fini_section_name(".fini");
+ static ConstString ctors_section_name(".ctors");
+ static ConstString dtors_section_name(".dtors");
+
+ static ConstString data_section_name(".data");
+ static ConstString rodata_section_name(".rodata");
+ static ConstString rodata1_section_name(".rodata1");
+ static ConstString data2_section_name(".data1");
+ static ConstString bss_section_name(".bss");
+
+ for (i=0; i<num_symbols; ++i)
+ {
+ // if (symtab_data.GetU32(&offset, &symbol.st_name, 3) == 0)
+ // break;
+
+ if (!symtab_data.ValidOffsetForDataOfSize(offset, sizeof(Elf32_Sym)))
+ break;
+
+ symbol.st_name = symtab_data.GetU32 (&offset);
+ symbol.st_value = symtab_data.GetU32 (&offset);
+ symbol.st_size = symtab_data.GetU32 (&offset);
+ symbol.st_info = symtab_data.GetU8 (&offset);
+ symbol.st_other = symtab_data.GetU8 (&offset);
+ symbol.st_shndx = symtab_data.GetU16 (&offset);
+
+ Section * symbol_section = NULL;
+ SymbolType symbol_type = eSymbolTypeInvalid;
+
+ switch (symbol.st_shndx)
+ {
+ case SHN_ABS:
+ symbol_type = eSymbolTypeAbsolute;
+ break;
+ case SHN_UNDEF:
+ symbol_type = eSymbolTypeUndefined;
+ break;
+ default:
+ symbol_section = section_list->GetSectionAtIndex (symbol.st_shndx).get();
+ break;
+ }
+
+ switch (ELF32_ST_BIND (symbol.st_info))
+ {
+ default:
+ case STT_NOTYPE:
+ // The symbol's type is not specified.
+ break;
+
+ case STT_OBJECT:
+ // The symbol is associated with a data object, such as a variable, an array, etc.
+ symbol_type == eSymbolTypeData;
+ break;
+
+ case STT_FUNC:
+ // The symbol is associated with a function or other executable code.
+ symbol_type == eSymbolTypeCode;
+ break;
+
+ case STT_SECTION:
+ // The symbol is associated with a section. Symbol table entries of
+ // this type exist primarily for relocation and normally have
+ // STB_LOCAL binding.
+ break;
+
+ case STT_FILE:
+ // Conventionally, the symbol's name gives the name of the source
+ // file associated with the object file. A file symbol has STB_LOCAL
+ // binding, its section index is SHN_ABS, and it precedes the other
+ // STB_LOCAL symbols for the file, if it is present.
+ symbol_type == eSymbolTypeObjectFile;
+ break;
+ }
+
+ if (symbol_type == eSymbolTypeInvalid)
+ {
+ if (symbol_section)
+ {
+ const ConstString §_name = symbol_section->GetName();
+ if (sect_name == text_section_name ||
+ sect_name == init_section_name ||
+ sect_name == fini_section_name ||
+ sect_name == ctors_section_name ||
+ sect_name == dtors_section_name)
+ {
+ symbol_type = eSymbolTypeCode;
+ }
+ else
+ if (sect_name == data_section_name ||
+ sect_name == data2_section_name ||
+ sect_name == rodata_section_name ||
+ sect_name == rodata1_section_name ||
+ sect_name == bss_section_name)
+ {
+ symbol_type = eSymbolTypeData;
+ }
+ }
+ }
+
+ uint64_t symbol_value = symbol.st_value;
+ if (symbol_section != NULL)
+ symbol_value -= symbol_section->GetFileAddress();
+ const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
+
+ Symbol dc_symbol(i, // ID is the original symbol table index
+ symbol_name, // symbol name
+ false, // Is the symbol name mangled?
+ symbol_type, // type of this symbol
+ ELF32_ST_BIND (symbol.st_info) == STB_GLOBAL, // Is this globally visible?
+ false, // Is this symbol debug info?
+ false, // Is this symbol a trampoline?
+ false, // Is this symbol artificial?
+ symbol_section, // section pointer if symbol_value is an offset within a section, else NULL
+ symbol_value, // offset from section if section is non-NULL, else the value for this symbol
+ symbol.st_size, // size in bytes of this symbol
+ symbol.st_other << 8 | symbol.st_info); // symbol flags
+ symtab->AddSymbol(dc_symbol);
+ }
+}
+
+
+Symtab *
+ObjectFileELF::GetSymtab()
+{
+ if (m_symtab_ap.get() == NULL)
+ {
+ m_symtab_ap.reset(new Symtab(this));
+
+ if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+ {
+ uint32_t symtab_idx = UINT32_MAX;
+ uint32_t dynsym_idx = UINT32_MAX;
+ uint32_t sh_idx = 0;
+ const size_t num_sections = m_section_headers.size();
+ for (sh_idx = 0; sh_idx < num_sections; ++sh_idx)
+ {
+ if (m_section_headers[sh_idx].sh_type == SHT_SYMTAB)
+ {
+ symtab_idx = sh_idx;
+ break;
+ }
+ if (m_section_headers[sh_idx].sh_type == SHT_DYNSYM)
+ {
+ dynsym_idx = sh_idx;
+ }
+ }
+
+ SectionList *section_list = NULL;
+ static ConstString g_symtab(".symtab");
+ static ConstString g_strtab(".strtab");
+ static ConstString g_dynsym(".dynsym");
+ static ConstString g_dynstr(".dynstr");
+ // Check if we found a full symbol table?
+ if (symtab_idx < num_sections)
+ {
+ section_list = GetSectionList();
+ if (section_list)
+ {
+ Section *symtab_section = section_list->FindSectionByName(g_symtab).get();
+ Section *strtab_section = section_list->FindSectionByName(g_strtab).get();
+ if (symtab_section && strtab_section)
+ {
+ DataExtractor symtab_data;
+ DataExtractor strtab_data;
+ if (symtab_section->ReadSectionDataFromObjectFile (this, symtab_data) > 0 &&
+ strtab_section->ReadSectionDataFromObjectFile (this, strtab_data) > 0)
+ {
+ ParseSymbols (m_symtab_ap.get(), section_list, m_section_headers[symtab_idx], symtab_data, strtab_data);
+ }
+ }
+ }
+ }
+ // Check if we found a reduced symbol table that gets used for dynamic linking?
+ else if (dynsym_idx < num_sections)
+ {
+ section_list = GetSectionList();
+ if (section_list)
+ {
+ Section *dynsym_section = section_list->FindSectionByName(g_dynsym).get();
+ Section *dynstr_section = section_list->FindSectionByName(g_dynstr).get();
+ if (dynsym_section && dynstr_section)
+ {
+ DataExtractor dynsym_data;
+ DataExtractor dynstr_data;
+ if (dynsym_section->ReadSectionDataFromObjectFile (this, dynsym_data) > 0 &&
+ dynstr_section->ReadSectionDataFromObjectFile (this, dynstr_data) > 0)
+ {
+ ParseSymbols (m_symtab_ap.get(), section_list, m_section_headers[dynsym_idx], dynsym_data, dynstr_data);
+ }
+ }
+ }
+ }
+ }
+ }
+ return m_symtab_ap.get();
+}
+
+//
+////----------------------------------------------------------------------
+//// GetNListSymtab
+////----------------------------------------------------------------------
+//bool
+//ELF32RuntimeFileParser::GetNListSymtab(BinaryDataRef& stabs_data, BinaryDataRef& stabstr_data, bool locals_only, uint32_t& value_size)
+//{
+// value_size = 4; // Size in bytes of the nlist n_value member
+// return GetSectionInfo(GetSectionIndexByName(".stab"), NULL, NULL, NULL, NULL, NULL, NULL, &stabs_data, NULL) &&
+// GetSectionInfo(GetSectionIndexByName(".stabstr"), NULL, NULL, NULL, NULL, NULL, NULL, &stabstr_data, NULL);
+//}
+//
+//===----------------------------------------------------------------------===//
+// Dump
+//
+// Dump the specifics of the runtime file container (such as any headers
+// segments, sections, etc).
+//----------------------------------------------------------------------
+void
+ObjectFileELF::Dump(Stream *s)
+{
+ DumpELFHeader(s, m_header);
+ s->EOL();
+ DumpELFProgramHeaders(s);
+ s->EOL();
+ DumpELFSectionHeaders(s);
+ s->EOL();
+ SectionList *section_list = GetSectionList();
+ if (section_list)
+ section_list->Dump(s, NULL, true);
+ Symtab *symtab = GetSymtab();
+ if (symtab)
+ symtab->Dump(s, NULL);
+ s->EOL();
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader
+//
+// Dump the ELF header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader(Stream *s, const Elf32_Ehdr& header)
+{
+
+ s->PutCString ("ELF Header\n");
+ s->Printf ("e_ident[EI_MAG0 ] = 0x%2.2x\n", header.e_ident[EI_MAG0]);
+ s->Printf ("e_ident[EI_MAG1 ] = 0x%2.2x '%c'\n", header.e_ident[EI_MAG1], header.e_ident[EI_MAG1]);
+ s->Printf ("e_ident[EI_MAG2 ] = 0x%2.2x '%c'\n", header.e_ident[EI_MAG2], header.e_ident[EI_MAG2]);
+ s->Printf ("e_ident[EI_MAG3 ] = 0x%2.2x '%c'\n", header.e_ident[EI_MAG3], header.e_ident[EI_MAG3]);
+ s->Printf ("e_ident[EI_CLASS ] = 0x%2.2x\n", header.e_ident[EI_CLASS]);
+ s->Printf ("e_ident[EI_DATA ] = 0x%2.2x ", header.e_ident[EI_DATA]);
+ DumpELFHeader_e_ident_EI_DATA(s, header.e_ident[EI_DATA]);
+ s->Printf ("\ne_ident[EI_VERSION] = 0x%2.2x\n", header.e_ident[EI_VERSION]);
+ s->Printf ("e_ident[EI_PAD ] = 0x%2.2x\n", header.e_ident[EI_PAD]);
+
+ s->Printf("e_type = 0x%4.4x ", header.e_type);
+ DumpELFHeader_e_type(s, header.e_type);
+ s->Printf("\ne_machine = 0x%4.4x\n", header.e_machine);
+ s->Printf("e_version = 0x%8.8x\n", header.e_version);
+ s->Printf("e_entry = 0x%8.8x\n", header.e_entry);
+ s->Printf("e_phoff = 0x%8.8x\n", header.e_phoff);
+ s->Printf("e_shoff = 0x%8.8x\n", header.e_shoff);
+ s->Printf("e_flags = 0x%8.8x\n", header.e_flags);
+ s->Printf("e_ehsize = 0x%4.4x\n", header.e_ehsize);
+ s->Printf("e_phentsize = 0x%4.4x\n", header.e_phentsize);
+ s->Printf("e_phnum = 0x%4.4x\n", header.e_phnum);
+ s->Printf("e_shentsize = 0x%4.4x\n", header.e_shentsize);
+ s->Printf("e_shnum = 0x%4.4x\n", header.e_shnum);
+ s->Printf("e_shstrndx = 0x%4.4x\n", header.e_shstrndx);
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader_e_type
+//
+// Dump an token value for the ELF header member e_type
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader_e_type(Stream *s, uint16_t e_type)
+{
+ switch (e_type)
+ {
+ case ET_NONE: *s << "ET_NONE"; break;
+ case ET_REL: *s << "ET_REL"; break;
+ case ET_EXEC: *s << "ET_EXEC"; break;
+ case ET_DYN: *s << "ET_DYN"; break;
+ case ET_CORE: *s << "ET_CORE"; break;
+ default:
+ break;
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader_e_ident_EI_DATA
+//
+// Dump an token value for the ELF header member e_ident[EI_DATA]
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader_e_ident_EI_DATA(Stream *s, uint16_t ei_data)
+{
+ switch (ei_data)
+ {
+ case ELFDATANONE: *s << "ELFDATANONE"; break;
+ case ELFDATA2LSB: *s << "ELFDATA2LSB - Little Endian"; break;
+ case ELFDATA2MSB: *s << "ELFDATA2MSB - Big Endian"; break;
+ default:
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader
+//
+// Dump a single ELF program header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader(Stream *s, const Elf32_Phdr& ph)
+{
+ DumpELFProgramHeader_p_type(s, ph.p_type);
+ s->Printf(" %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x (", ph.p_offset, ph.p_vaddr, ph.p_paddr, ph.p_filesz, ph.p_memsz, ph.p_flags);
+ DumpELFProgramHeader_p_flags(s, ph.p_flags);
+ s->Printf(") %8.8x", ph.p_align);
+}
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader_p_type
+//
+// Dump an token value for the ELF program header member p_type which
+// describes the type of the program header
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader_p_type(Stream *s, Elf32_Word p_type)
+{
+ const int kStrWidth = 10;
+ switch (p_type)
+ {
+ CASE_AND_STREAM(s, PT_NULL , kStrWidth);
+ CASE_AND_STREAM(s, PT_LOAD , kStrWidth);
+ CASE_AND_STREAM(s, PT_DYNAMIC , kStrWidth);
+ CASE_AND_STREAM(s, PT_INTERP , kStrWidth);
+ CASE_AND_STREAM(s, PT_NOTE , kStrWidth);
+ CASE_AND_STREAM(s, PT_SHLIB , kStrWidth);
+ CASE_AND_STREAM(s, PT_PHDR , kStrWidth);
+ default:
+ s->Printf("0x%8.8x%*s", p_type, kStrWidth - 10, "");
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader_p_flags
+//
+// Dump an token value for the ELF program header member p_flags
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader_p_flags(Stream *s, Elf32_Word p_flags)
+{
+ *s << ((p_flags & PF_X) ? "PF_X" : " ")
+ << (((p_flags & PF_X) && (p_flags & PF_W)) ? '+' : ' ')
+ << ((p_flags & PF_W) ? "PF_W" : " ")
+ << (((p_flags & PF_W) && (p_flags & PF_R)) ? '+' : ' ')
+ << ((p_flags & PF_R) ? "PF_R" : " ");
+}
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeaders
+//
+// Dump all of the ELF program header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeaders(Stream *s)
+{
+ if (ParseProgramHeaders())
+ {
+ s->PutCString("Program Headers\n");
+ s->PutCString("IDX p_type p_offset p_vaddr p_paddr p_filesz p_memsz p_flags p_align\n");
+ s->PutCString("==== ---------- -------- -------- -------- -------- -------- ------------------------- --------\n");
+
+ uint32_t idx = 0;
+ ProgramHeaderCollConstIter pos;
+
+ for (pos = m_program_headers.begin(); pos != m_program_headers.end(); ++pos, ++idx)
+ {
+ s->Printf ("[%2u] ", idx);
+ ObjectFileELF::DumpELFProgramHeader(s, *pos);
+ s->EOL();
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader
+//
+// Dump a single ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader(Stream *s, const Elf32_Shdr& sh)
+{
+ s->Printf ("%8.8x ", sh.sh_name);
+ DumpELFSectionHeader_sh_type(s, sh.sh_type);
+ s->Printf (" %8.8x (", sh.sh_flags);
+ DumpELFSectionHeader_sh_flags(s, sh.sh_flags);
+ s->Printf (") %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x",
+ sh.sh_addr, sh.sh_offset, sh.sh_size, sh.sh_link, sh.sh_info, sh.sh_addralign, sh.sh_entsize);
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader_sh_type
+//
+// Dump an token value for the ELF section header member sh_type which
+// describes the type of the section
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader_sh_type(Stream *s, Elf32_Word sh_type)
+{
+ const int kStrWidth = 12;
+ switch (sh_type)
+ {
+ CASE_AND_STREAM(s, SHT_NULL , kStrWidth);
+ CASE_AND_STREAM(s, SHT_PROGBITS , kStrWidth);
+ CASE_AND_STREAM(s, SHT_SYMTAB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_STRTAB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_RELA , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HASH , kStrWidth);
+ CASE_AND_STREAM(s, SHT_DYNAMIC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_NOTE , kStrWidth);
+ CASE_AND_STREAM(s, SHT_NOBITS , kStrWidth);
+ CASE_AND_STREAM(s, SHT_REL , kStrWidth);
+ CASE_AND_STREAM(s, SHT_SHLIB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_DYNSYM , kStrWidth);
+ CASE_AND_STREAM(s, SHT_LOPROC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HIPROC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_LOUSER , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HIUSER , kStrWidth);
+ default:
+ s->Printf("0x%8.8x%*s", sh_type, kStrWidth - 10, "");
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader_sh_flags
+//
+// Dump an token value for the ELF section header member sh_flags
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader_sh_flags(Stream *s, Elf32_Word sh_flags)
+{
+ *s << ((sh_flags & SHF_WRITE) ? "WRITE" : " ")
+ << (((sh_flags & SHF_WRITE) && (sh_flags & SHF_ALLOC)) ? '+' : ' ')
+ << ((sh_flags & SHF_ALLOC) ? "ALLOC" : " ")
+ << (((sh_flags & SHF_ALLOC) && (sh_flags & SHF_EXECINSTR)) ? '+' : ' ')
+ << ((sh_flags & SHF_EXECINSTR) ? "EXECINSTR" : " ");
+}
+//----------------------------------------------------------------------
+// DumpELFSectionHeaders
+//
+// Dump all of the ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeaders(Stream *s)
+{
+ if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+ {
+ s->PutCString("Section Headers\n");
+ s->PutCString("IDX name type flags addr offset size link info addralgn entsize Name\n");
+ s->PutCString("==== -------- ------------ -------------------------------- -------- -------- -------- -------- -------- -------- -------- ====================\n");
+
+ uint32_t idx = 0;
+ SectionHeaderCollConstIter pos;
+
+ for (pos = m_section_headers.begin(); pos != m_section_headers.end(); ++pos, ++idx)
+ {
+ s->Printf ("[%2u] ", idx);
+ ObjectFileELF::DumpELFSectionHeader(s, *pos);
+ const char* section_name = m_shstr_data.PeekCStr(pos->sh_name);
+ if (section_name)
+ *s << ' ' << section_name << "\n";
+ }
+ }
+}
+
+static uint32_t
+ELFMachineToMachCPU(Elf32_Half machine)
+{
+ switch (machine)
+ {
+ case EM_SPARC: return CPU_TYPE_SPARC;
+ case EM_386: return CPU_TYPE_I386;
+ case EM_68K: return CPU_TYPE_MC680x0;
+ case EM_88K: return CPU_TYPE_MC88000;
+ case EM_860: return CPU_TYPE_I860;
+ case EM_MIPS: return 8; // commented out in mach/machine.h
+ case EM_PPC: return CPU_TYPE_POWERPC;
+ case EM_PPC64: return CPU_TYPE_POWERPC64;
+ case EM_ARM: return 12; // commented out in mach/machine.h
+ }
+ return 0;
+}
+
+bool
+ObjectFileELF::GetTargetTriple (ConstString &target_triple)
+{
+ static ConstString g_target_triple;
+
+ if (g_target_triple)
+ {
+ target_triple = g_target_triple;
+ }
+ else
+ {
+ std::string triple;
+ switch (m_header.e_machine)
+ {
+ case EM_SPARC: triple.assign("sparc-"); break;
+ case EM_386: triple.assign("i386-"); break;
+ case EM_68K: triple.assign("68k-"); break;
+ case EM_88K: triple.assign("88k-"); break;
+ case EM_860: triple.assign("i860-"); break;
+ case EM_MIPS: triple.assign("mips-"); break;
+ case EM_PPC: triple.assign("powerpc-"); break;
+ case EM_PPC64: triple.assign("powerpc64-"); break;
+ case EM_ARM: triple.assign("arm-"); break;
+ }
+ // TODO: determine if there is a vendor in the ELF? Default to "apple" for now
+ triple += "apple-";
+ // TODO: determine if there is an OS in the ELF? Default to "darwin" for now
+ triple += "darwin10";
+ g_target_triple.SetCString(triple.c_str());
+ target_triple = g_target_triple;
+ }
+ return !target_triple.IsEmpty();
+}
+
+
+//bool
+//ELF32RuntimeFileParser::GetArch(ArchSpec &arch) const
+//{
+// arch.SetCPUType(ELFMachineToMachCPU(m_header.e_machine));
+// arch.SetCPUSubtype(ArchSpec::eAny);
+// return true;
+//}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectFileELF::GetPluginName()
+{
+ return "ObjectFileELF";
+}
+
+const char *
+ObjectFileELF::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileELF::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectFileELF::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectFileELF::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectFileELF::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
new file mode 100644
index 0000000..5d5778c
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -0,0 +1,197 @@
+//===-- ObjectFileELF.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_ObjectFileELF_h_
+#define liblldb_ObjectFileELF_h_
+
+#include <stdint.h>
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "elf.h"
+
+//----------------------------------------------------------------------
+// This class needs to be hidden as eventually belongs in a plugin that
+// will export the ObjectFile protocol
+//----------------------------------------------------------------------
+class ObjectFileELF :
+ public lldb_private::ObjectFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectFile *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectFileELF (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectFileELF();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual size_t
+ GetAddressByteSize () const;
+
+ virtual lldb_private::Symtab *
+ GetSymtab();
+
+ virtual lldb_private::SectionList *
+ GetSectionList();
+
+ virtual void
+ Dump (lldb_private::Stream *s);
+
+ virtual bool
+ GetTargetTriple (lldb_private::ConstString &target_triple);
+
+ virtual bool
+ GetUUID (lldb_private::UUID* uuid);
+
+ virtual uint32_t
+ GetDependentModules(lldb_private::FileSpecList& files);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+
+protected:
+ typedef std::vector<Elf32_Phdr> ProgramHeaderColl;
+ typedef ProgramHeaderColl::iterator ProgramHeaderCollIter;
+ typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter;
+
+ typedef std::vector<Elf32_Shdr> SectionHeaderColl;
+ typedef SectionHeaderColl::iterator SectionHeaderCollIter;
+ typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter;
+
+ Elf32_Ehdr m_header;
+ ProgramHeaderColl m_program_headers;
+ SectionHeaderColl m_section_headers;
+ mutable std::auto_ptr<lldb_private::SectionList> m_sections_ap;
+ mutable std::auto_ptr<lldb_private::Symtab> m_symtab_ap;
+ lldb_private::DataExtractor m_shstr_data;
+
+ size_t
+ ParseSections ();
+
+ size_t
+ ParseSymtab (bool minimize);
+
+private:
+
+ // ELF header dump routines
+ static void
+ DumpELFHeader (lldb_private::Stream *s,
+ const Elf32_Ehdr& header);
+
+ static void
+ DumpELFHeader_e_ident_EI_DATA (lldb_private::Stream *s,
+ uint16_t ei_data);
+ static void
+ DumpELFHeader_e_type (lldb_private::Stream *s,
+ uint16_t e_type);
+
+ // ELF program header dump routines
+ void
+ DumpELFProgramHeaders (lldb_private::Stream *s);
+
+ static void
+ DumpELFProgramHeader (lldb_private::Stream *s,
+ const Elf32_Phdr& ph);
+
+ static void
+ DumpELFProgramHeader_p_type (lldb_private::Stream *s,
+ Elf32_Word p_type);
+
+ static void
+ DumpELFProgramHeader_p_flags (lldb_private::Stream *s,
+ Elf32_Word p_flags);
+
+ // ELF section header dump routines
+ void
+ DumpELFSectionHeaders (lldb_private::Stream *s);
+
+ static void
+ DumpELFSectionHeader (lldb_private::Stream *s,
+ const Elf32_Shdr& sh);
+
+ static void
+ DumpELFSectionHeader_sh_type (lldb_private::Stream *s,
+ Elf32_Word sh_type);
+
+ static void
+ DumpELFSectionHeader_sh_flags (lldb_private::Stream *s,
+ Elf32_Word sh_flags);
+
+ size_t
+ ParseProgramHeaders ();
+
+ size_t
+ ParseSectionHeaders ();
+
+ size_t
+ GetSectionHeaderStringTable ();
+
+ uint32_t
+ GetSectionIndexByName (const char *name);
+};
+
+#endif // #ifndef liblldb_ObjectFileELF_h_
diff --git a/source/Plugins/ObjectFile/ELF/elf.h b/source/Plugins/ObjectFile/ELF/elf.h
new file mode 100644
index 0000000..9d08119
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/elf.h
@@ -0,0 +1,240 @@
+//===-- elf.h ---------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __elf_h__
+#define __elf_h__
+
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Addr;
+typedef uint32_t Elf32_Off;
+
+
+#define EI_NIDENT 16
+
+//----------------------------------------------------------------------
+// ELF Header
+//----------------------------------------------------------------------
+typedef struct Elf32_Ehdr_Tag
+{
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+//----------------------------------------------------------------------
+// e_type
+//
+// This member identifies the object file type.
+//----------------------------------------------------------------------
+#define ET_NONE 0 // No file type
+#define ET_REL 1 // Relocatable file
+#define ET_EXEC 2 // Executable file
+#define ET_DYN 3 // Shared object file
+#define ET_CORE 4 // Core file
+#define ET_LOPROC 0xff00 // Processor-specific
+#define ET_HIPROC 0xffff // Processor-specific
+
+//----------------------------------------------------------------------
+// e_machine
+//
+// Machine Type
+//----------------------------------------------------------------------
+#define EM_NONE 0 // No machine
+#define EM_M32 1 // AT&T WE 32100
+#define EM_SPARC 2 // SPARC
+#define EM_386 3 // Intel 80386
+#define EM_68K 4 // Motorola 68000
+#define EM_88K 5 // Motorola 88000
+#define EM_860 7 // Intel 80860
+#define EM_MIPS 8 // MIPS RS3000
+#define EM_PPC 20 // PowerPC
+#define EM_PPC64 21 // PowerPC64
+#define EM_ARM 40 // ARM
+
+
+//----------------------------------------------------------------------
+// e_ident indexes
+//----------------------------------------------------------------------
+#define EI_MAG0 0 // File identification
+#define EI_MAG1 1 // File identification
+#define EI_MAG2 2 // File identification
+#define EI_MAG3 3 // File identification
+#define EI_CLASS 4 // File class
+#define EI_DATA 5 // Data encoding
+#define EI_VERSION 6 // File version
+#define EI_PAD 7 // Start of padding bytes
+
+
+//----------------------------------------------------------------------
+// EI_DATA definitions
+//----------------------------------------------------------------------
+#define ELFDATANONE 0 // Invalid data encoding
+#define ELFDATA2LSB 1 // Little Endian
+#define ELFDATA2MSB 2 // Big Endian
+
+//----------------------------------------------------------------------
+// Section Header
+//----------------------------------------------------------------------
+typedef struct Elf32_Shdr_Tag
+{
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+//----------------------------------------------------------------------
+// Section Types (sh_type)
+//----------------------------------------------------------------------
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#define SHT_LOPROC 0x70000000
+#define SHT_HIPROC 0x7fffffff
+#define SHT_LOUSER 0x80000000
+#define SHT_HIUSER 0xffffffff
+
+//----------------------------------------------------------------------
+// Special Section Indexes
+//----------------------------------------------------------------------
+#define SHN_UNDEF 0
+#define SHN_LORESERVE 0xff00
+#define SHN_LOPROC 0xff00
+#define SHN_HIPROC 0xff1f
+#define SHN_ABS 0xfff1
+#define SHN_COMMON 0xfff2
+#define SHN_HIRESERVE 0xffff
+
+//----------------------------------------------------------------------
+// Section Attribute Flags (sh_flags)
+//----------------------------------------------------------------------
+#define SHF_WRITE 0x1
+#define SHF_ALLOC 0x2
+#define SHF_EXECINSTR 0x4
+#define SHF_MASKPROC 0xf0000000
+
+
+//----------------------------------------------------------------------
+// Symbol Table Entry Header
+//----------------------------------------------------------------------
+typedef struct Elf32_Sym_Tag
+{
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+
+#define ELF32_ST_BIND(i) ((i)>>4)
+#define ELF32_ST_TYPE(i) ((i)&0xf)
+#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
+
+// ST_BIND
+#define STB_LOCAL 0
+#define STB_GLOBAL 1
+#define STB_WEAK 2
+#define STB_LOPROC 13
+#define STB_HIPROC 15
+
+// ST_TYPE
+#define STT_NOTYPE 0
+#define STT_OBJECT 1
+#define STT_FUNC 2
+#define STT_SECTION 3
+#define STT_FILE 4
+#define STT_LOPROC 13
+#define STT_HIPROC 15
+
+
+//----------------------------------------------------------------------
+// Relocation Entries
+//----------------------------------------------------------------------
+typedef struct Elf32_Rel_Tag
+{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct Elf32_Rela_Tag
+{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+#define ELF32_R_SYM(i) ((i)>>8)
+#define ELF32_R_TYPE(i) ((unsignedchar)(i))
+#define ELF32_R_INFO(s,t) (((s)<<8)+(unsignedchar)(t))
+
+
+//----------------------------------------------------------------------
+// Program Headers
+//----------------------------------------------------------------------
+typedef struct Elf32_Phdr_Tag
+{
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+//----------------------------------------------------------------------
+// Program Header Type (p_type)
+//----------------------------------------------------------------------
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+
+#define PF_X (1 << 0) // executable
+#define PF_W (1 << 1) // writable
+#define PF_R (1 << 2) // readable
+
+
+#endif // __elf_h__
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
new file mode 100644
index 0000000..682a116
--- /dev/null
+++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -0,0 +1,1311 @@
+//===-- ObjectFileMachO.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectFileMachO.h"
+
+#include <mach-o/nlist.h>
+#include <mach-o/stab.h>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#ifndef S_DTRACE_DOF
+// section contains DTrace Object Format
+#define S_DTRACE_DOF 0xf
+#endif
+
+#ifndef S_LAZY_DYLIB_SYMBOL_POINTERS
+// section with only lazy symbol pointers to lazy loaded dylibs
+#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+void
+ObjectFileMachO::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+ObjectFileMachO::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectFileMachO::GetPluginNameStatic()
+{
+ return "object-file.mach-o";
+}
+
+const char *
+ObjectFileMachO::GetPluginDescriptionStatic()
+{
+ return "Mach-o object file reader (32 and 64 bit)";
+}
+
+
+ObjectFile *
+ObjectFileMachO::CreateInstance (Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length)
+{
+ if (ObjectFileMachO::MagicBytesMatch(dataSP))
+ {
+ std::auto_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module, dataSP, file, offset, length));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
+}
+
+
+static uint32_t
+MachHeaderSizeFromMagic(uint32_t magic)
+{
+ switch (magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ return sizeof(struct mach_header);
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ return sizeof(struct mach_header_64);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+bool
+ObjectFileMachO::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ uint32_t offset = 0;
+ uint32_t magic = data.GetU32(&offset);
+ return MachHeaderSizeFromMagic(magic) != 0;
+}
+
+
+ObjectFileMachO::ObjectFileMachO(Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length) :
+ ObjectFile(module, file, offset, length, dataSP),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_header(),
+ m_sections_ap(),
+ m_symtab_ap()
+{
+ ::bzero (&m_header, sizeof(m_header));
+ ::bzero (&m_dysymtab, sizeof(m_dysymtab));
+}
+
+
+ObjectFileMachO::~ObjectFileMachO()
+{
+}
+
+
+bool
+ObjectFileMachO::ParseHeader ()
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ bool can_parse = false;
+ uint32_t offset = 0;
+ m_data.SetByteOrder (eByteOrderHost);
+ // Leave magic in the original byte order
+ m_header.magic = m_data.GetU32(&offset);
+ switch (m_header.magic)
+ {
+ case MH_MAGIC:
+ m_data.SetByteOrder (eByteOrderHost);
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_MAGIC_64:
+ m_data.SetByteOrder (eByteOrderHost);
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM:
+ m_data.SetByteOrder(eByteOrderHost == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM_64:
+ m_data.SetByteOrder(eByteOrderHost == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (can_parse)
+ {
+ m_data.GetU32(&offset, &m_header.cputype, 6);
+
+ ArchSpec mach_arch(m_header.cputype, m_header.cpusubtype);
+ if (mach_arch == m_module->GetArchitecture())
+ {
+ // Read in all only the load command data
+ DataBufferSP data_sp(m_file.ReadFileContents(m_offset, m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic)));
+ m_data.SetData (data_sp);
+ return true;
+ }
+ }
+ else
+ {
+ memset(&m_header, 0, sizeof(struct mach_header));
+ }
+ return false;
+}
+
+
+ByteOrder
+ObjectFileMachO::GetByteOrder () const
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ return m_data.GetByteOrder ();
+}
+
+
+size_t
+ObjectFileMachO::GetAddressByteSize () const
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ return m_data.GetAddressByteSize ();
+}
+
+
+Symtab *
+ObjectFileMachO::GetSymtab()
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ if (m_symtab_ap.get() == NULL)
+ {
+ m_symtab_ap.reset(new Symtab(this));
+ ParseSymtab(false);
+ }
+ return m_symtab_ap.get();
+}
+
+
+SectionList *
+ObjectFileMachO::GetSectionList()
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ if (m_sections_ap.get() == NULL)
+ {
+ m_sections_ap.reset(new SectionList());
+ ParseSections();
+ }
+ return m_sections_ap.get();
+}
+
+
+size_t
+ObjectFileMachO::ParseSections ()
+{
+ lldb::user_id_t segID = 0;
+ lldb::user_id_t sectID = 0;
+ struct segment_command_64 load_cmd;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ //bool dump_sections = false;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t load_cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64)
+ {
+ if (m_data.GetU8(&offset, (uint8_t*)load_cmd.segname, 16))
+ {
+ load_cmd.vmaddr = m_data.GetAddress(&offset);
+ load_cmd.vmsize = m_data.GetAddress(&offset);
+ load_cmd.fileoff = m_data.GetAddress(&offset);
+ load_cmd.filesize = m_data.GetAddress(&offset);
+ if (m_data.GetU32(&offset, &load_cmd.maxprot, 4))
+ {
+ // Keep a list of mach segments around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_segments.push_back (load_cmd);
+
+ ConstString segment_name (load_cmd.segname, std::min<int>(strlen(load_cmd.segname), sizeof(load_cmd.segname)));
+ // Use a segment ID of the segment index shifted left by 8 so they
+ // never conflict with any of the sections.
+ SectionSP segment_sp;
+ if (segment_name)
+ {
+ segment_sp.reset(new Section (NULL,
+ GetModule(), // Module to which this section belongs
+ ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
+ segment_name, // Name of this section
+ eSectionTypeContainer, // This section is a container of other sections.
+ load_cmd.vmaddr, // File VM address == addresses as they are found in the object file
+ load_cmd.vmsize, // VM size in bytes of this section
+ load_cmd.fileoff, // Offset to the data for this section in the file
+ load_cmd.filesize, // Size in bytes of this section as found in the the file
+ load_cmd.flags)); // Flags for this section
+
+ m_sections_ap->AddSection(segment_sp);
+ }
+
+ struct section_64 sect64;
+ ::bzero (§64, sizeof(sect64));
+ // Push a section into our mach sections for the section at
+ // index zero (NO_SECT)
+ m_mach_sections.push_back(sect64);
+ uint32_t segment_sect_idx;
+ const lldb::user_id_t first_segment_sectID = sectID + 1;
+
+
+ const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
+ for (segment_sect_idx=0; segment_sect_idx<load_cmd.nsects; ++segment_sect_idx)
+ {
+ if (m_data.GetU8(&offset, (uint8_t*)sect64.sectname, sizeof(sect64.sectname)) == NULL)
+ break;
+ if (m_data.GetU8(&offset, (uint8_t*)sect64.segname, sizeof(sect64.segname)) == NULL)
+ break;
+ sect64.addr = m_data.GetAddress(&offset);
+ sect64.size = m_data.GetAddress(&offset);
+
+ if (m_data.GetU32(&offset, §64.offset, num_u32s) == NULL)
+ break;
+
+ // Keep a list of mach sections around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_sections.push_back (sect64);
+
+ ConstString section_name (sect64.sectname, std::min<size_t>(strlen(sect64.sectname), sizeof(sect64.sectname)));
+ if (!segment_name)
+ {
+ // We have a segment with no name so we need to conjure up
+ // segments that correspond to the section's segname if there
+ // isn't already such a section. If there is such a section,
+ // we resize the section so that it spans all sections.
+ // We also mark these sections as fake so address matches don't
+ // hit if they land in the gaps between the child sections.
+ segment_name.SetTrimmedCStringWithLength(sect64.segname, sizeof(sect64.segname));
+ segment_sp = m_sections_ap->FindSectionByName (segment_name);
+ if (segment_sp.get())
+ {
+ Section *segment = segment_sp.get();
+ // Grow the section size as needed.
+ const lldb::addr_t sect64_min_addr = sect64.addr;
+ const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size;
+ const lldb::addr_t curr_seg_byte_size = segment->GetByteSize();
+ const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress();
+ const lldb::addr_t curr_seg_max_addr = curr_seg_min_addr + curr_seg_byte_size;
+ if (sect64_min_addr >= curr_seg_min_addr)
+ {
+ const lldb::addr_t new_seg_byte_size = sect64_max_addr - curr_seg_min_addr;
+ // Only grow the section size if needed
+ if (new_seg_byte_size > curr_seg_byte_size)
+ segment->SetByteSize (new_seg_byte_size);
+ }
+ else
+ {
+ // We need to change the base address of the segment and
+ // adjust the child section offsets for all existing children.
+ const lldb::addr_t slide_amount = sect64_min_addr - curr_seg_min_addr;
+ segment->Slide(slide_amount, false);
+ segment->GetChildren().Slide (-slide_amount, false);
+ segment->SetByteSize (curr_seg_max_addr - sect64_min_addr);
+ }
+ }
+ else
+ {
+ // Create a fake section for the section's named segment
+ segment_sp.reset(new Section(segment_sp.get(), // Parent section
+ GetModule(), // Module to which this section belongs
+ ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
+ segment_name, // Name of this section
+ eSectionTypeContainer, // This section is a container of other sections.
+ sect64.addr, // File VM address == addresses as they are found in the object file
+ sect64.size, // VM size in bytes of this section
+ sect64.offset, // Offset to the data for this section in the file
+ sect64.offset ? sect64.size : 0, // Size in bytes of this section as found in the the file
+ load_cmd.flags)); // Flags for this section
+ segment_sp->SetIsFake(true);
+ m_sections_ap->AddSection(segment_sp);
+ }
+ }
+ assert (segment_sp.get());
+
+ uint32_t mach_sect_type = sect64.flags & SECTION_TYPE;
+ static ConstString g_sect_name_objc_data ("__objc_data");
+ static ConstString g_sect_name_objc_msgrefs ("__objc_msgrefs");
+ static ConstString g_sect_name_objc_selrefs ("__objc_selrefs");
+ static ConstString g_sect_name_objc_classrefs ("__objc_classrefs");
+ static ConstString g_sect_name_objc_superrefs ("__objc_superrefs");
+ static ConstString g_sect_name_objc_const ("__objc_const");
+ static ConstString g_sect_name_objc_classlist ("__objc_classlist");
+ static ConstString g_sect_name_cfstring ("__cfstring");
+ SectionType sect_type = eSectionTypeOther;
+
+ if (section_name == g_sect_name_objc_selrefs)
+ {
+ sect_type = eSectionTypeDataCStringPointers;
+ }
+ else if (section_name == g_sect_name_objc_msgrefs)
+ {
+ sect_type = eSectionTypeDataObjCMessageRefs;
+ }
+ else if (section_name == g_sect_name_objc_data ||
+ section_name == g_sect_name_objc_classrefs ||
+ section_name == g_sect_name_objc_superrefs ||
+ section_name == g_sect_name_objc_const ||
+ section_name == g_sect_name_objc_classlist)
+ {
+ sect_type = eSectionTypeDataPointers;
+ }
+ else if (section_name == g_sect_name_cfstring)
+ {
+ sect_type = eSectionTypeDataObjCCFStrings;
+ }
+
+ if (sect_type == eSectionTypeOther)
+ {
+ switch (mach_sect_type)
+ {
+ // TODO: categorize sections by other flags for regular sections
+ case S_REGULAR:
+
+ sect_type = eSectionTypeOther;
+ break;
+ case S_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
+ case S_CSTRING_LITERALS: sect_type = eSectionTypeDataCString; break; // section with only literal C strings
+ case S_4BYTE_LITERALS: sect_type = eSectionTypeData4; break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS: sect_type = eSectionTypeData8; break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS: sect_type = eSectionTypeCode; break; // section with only symbol stubs, byte size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for termination
+ case S_COALESCED: sect_type = eSectionTypeOther; break;
+ case S_GB_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
+ case S_INTERPOSING: sect_type = eSectionTypeCode; break; // section with only pairs of function pointers for interposing
+ case S_16BYTE_LITERALS: sect_type = eSectionTypeData16; break; // section with only 16 byte literals
+ case S_DTRACE_DOF: sect_type = eSectionTypeDebug; break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break;
+ default: break;
+ }
+ }
+
+ SectionSP section_sp(new Section(segment_sp.get(),
+ GetModule(),
+ ++sectID,
+ section_name,
+ sect_type,
+ sect64.addr - segment_sp->GetFileAddress(),
+ sect64.size,
+ sect64.offset,
+ sect64.offset == 0 ? 0 : sect64.size,
+ sect64.flags));
+ segment_sp->GetChildren().AddSection(section_sp);
+
+ if (segment_sp->IsFake())
+ {
+ segment_sp.reset();
+ segment_name.Clear();
+ }
+ }
+ if (m_header.filetype == MH_DSYM)
+ {
+ if (first_segment_sectID <= sectID)
+ {
+ lldb::user_id_t sect_uid;
+ for (sect_uid = first_segment_sectID; sect_uid <= sectID; ++sect_uid)
+ {
+ SectionSP curr_section_sp(segment_sp->GetChildren().FindSectionByID (sect_uid));
+ SectionSP next_section_sp;
+ if (sect_uid + 1 <= sectID)
+ next_section_sp = segment_sp->GetChildren().FindSectionByID (sect_uid+1);
+
+ if (curr_section_sp.get())
+ {
+ if (curr_section_sp->GetByteSize() == 0)
+ {
+ if (next_section_sp.get() != NULL)
+ curr_section_sp->SetByteSize ( next_section_sp->GetFileAddress() - curr_section_sp->GetFileAddress() );
+ else
+ curr_section_sp->SetByteSize ( load_cmd.vmsize );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (load_cmd.cmd == LC_DYSYMTAB)
+ {
+ m_dysymtab.cmd = load_cmd.cmd;
+ m_dysymtab.cmdsize = load_cmd.cmdsize;
+ m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
+ }
+
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
+// if (dump_sections)
+// {
+// StreamFile s(stdout);
+// m_sections_ap->Dump(&s, true);
+// }
+ return sectID; // Return the number of sections we registered with the module
+}
+
+class MachSymtabSectionInfo
+{
+public:
+
+ MachSymtabSectionInfo (SectionList *section_list) :
+ m_section_list (section_list),
+ m_section_infos()
+ {
+ // Get the number of sections down to a depth of 1 to include
+ // all segments and their sections, but no other sections that
+ // may be added for debug map or
+ m_section_infos.resize(section_list->GetNumSections(1));
+ }
+
+
+ Section *
+ GetSection (uint8_t n_sect, addr_t file_addr)
+ {
+ if (n_sect == 0)
+ return NULL;
+ if (n_sect < m_section_infos.size())
+ {
+ if (m_section_infos[n_sect].section == NULL)
+ {
+ Section *section = m_section_list->FindSectionByID (n_sect).get();
+ m_section_infos[n_sect].section = section;
+ assert (section != NULL);
+ m_section_infos[n_sect].vm_range.SetBaseAddress (section->GetFileAddress());
+ m_section_infos[n_sect].vm_range.SetByteSize (section->GetByteSize());
+ }
+ if (m_section_infos[n_sect].vm_range.Contains(file_addr))
+ return m_section_infos[n_sect].section;
+ }
+ return m_section_list->FindSectionContainingFileAddress(file_addr).get();
+ }
+
+protected:
+ struct SectionInfo
+ {
+ SectionInfo () :
+ vm_range(),
+ section (NULL)
+ {
+ }
+
+ VMRange vm_range;
+ Section *section;
+ };
+ SectionList *m_section_list;
+ std::vector<SectionInfo> m_section_infos;
+};
+
+
+
+size_t
+ObjectFileMachO::ParseSymtab (bool minimize)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "ObjectFileMachO::ParseSymtab () module = %s",
+ m_file.GetFilename().AsCString(""));
+ struct symtab_command symtab_load_command;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ // Read in the load command and load command size
+ if (m_data.GetU32(&offset, &symtab_load_command, 2) == NULL)
+ break;
+ // Watch for the symbol table load command
+ if (symtab_load_command.cmd == LC_SYMTAB)
+ {
+ // Read in the rest of the symtab load command
+ if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4))
+ {
+ Symtab *symtab = m_symtab_ap.get();
+ SectionList *section_list = GetSectionList();
+ assert(section_list);
+ const size_t addr_size = m_data.GetAddressByteSize();
+ const ByteOrder endian = m_data.GetByteOrder();
+ bool bit_width_32 = addr_size == 4;
+ const size_t nlist_size = bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
+
+ DataBufferSP symtab_data_sp(m_file.ReadFileContents(m_offset + symtab_load_command.symoff, symtab_load_command.nsyms * nlist_size));
+ DataBufferSP strtab_data_sp(m_file.ReadFileContents(m_offset + symtab_load_command.stroff, symtab_load_command.strsize));
+
+ const char *strtab_data = (const char *)strtab_data_sp->GetBytes();
+// DataExtractor symtab_data(symtab_data_sp, endian, addr_size);
+// DataExtractor strtab_data(strtab_data_sp, endian, addr_size);
+
+ static ConstString g_segment_name_TEXT ("__TEXT");
+ static ConstString g_segment_name_DATA ("__DATA");
+ static ConstString g_segment_name_OBJC ("__OBJC");
+ static ConstString g_section_name_eh_frame ("__eh_frame");
+ SectionSP text_section_sp(section_list->FindSectionByName(g_segment_name_TEXT));
+ SectionSP data_section_sp(section_list->FindSectionByName(g_segment_name_DATA));
+ SectionSP objc_section_sp(section_list->FindSectionByName(g_segment_name_OBJC));
+ SectionSP eh_frame_section_sp;
+ if (text_section_sp.get())
+ eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName (g_section_name_eh_frame);
+ else
+ eh_frame_section_sp = section_list->FindSectionByName (g_section_name_eh_frame);
+
+ uint8_t TEXT_eh_frame_sectID = eh_frame_section_sp.get() ? eh_frame_section_sp->GetID() : NO_SECT;
+ //uint32_t symtab_offset = 0;
+ const uint8_t* nlist_data = symtab_data_sp->GetBytes();
+ assert (symtab_data_sp->GetByteSize()/nlist_size >= symtab_load_command.nsyms);
+
+
+ if (endian != eByteOrderHost)
+ {
+ // ...
+ assert (!"UNIMPLEMENTED: Swap all nlist entries");
+ }
+ uint32_t N_SO_index = UINT_MAX;
+
+ MachSymtabSectionInfo section_info (section_list);
+ std::vector<uint32_t> N_FUN_indexes;
+ std::vector<uint32_t> N_NSYM_indexes;
+ std::vector<uint32_t> N_INCL_indexes;
+ std::vector<uint32_t> N_BRAC_indexes;
+ std::vector<uint32_t> N_COMM_indexes;
+ uint32_t nlist_idx = 0;
+ Symbol *symbol_ptr = NULL;
+
+ uint32_t sym_idx = 0;
+ Symbol *sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
+ uint32_t num_syms = symtab->GetNumSymbols();
+
+ //symtab->Reserve (symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
+ for (nlist_idx = 0; nlist_idx < symtab_load_command.nsyms; ++nlist_idx)
+ {
+ struct nlist_64 nlist;
+ if (bit_width_32)
+ {
+ struct nlist* nlist32_ptr = (struct nlist*)(nlist_data + (nlist_idx * nlist_size));
+ nlist.n_un.n_strx = nlist32_ptr->n_un.n_strx;
+ nlist.n_type = nlist32_ptr->n_type;
+ nlist.n_sect = nlist32_ptr->n_sect;
+ nlist.n_desc = nlist32_ptr->n_desc;
+ nlist.n_value = nlist32_ptr->n_value;
+ }
+ else
+ {
+ nlist = *((struct nlist_64*)(nlist_data + (nlist_idx * nlist_size)));
+ }
+
+ SymbolType type = eSymbolTypeInvalid;
+ const char* symbol_name = &strtab_data[nlist.n_un.n_strx];
+ if (symbol_name[0] == '\0')
+ symbol_name = NULL;
+ Section* symbol_section = NULL;
+ bool add_nlist = true;
+ bool is_debug = ((nlist.n_type & N_STAB) != 0);
+
+ assert (sym_idx < num_syms);
+
+ sym[sym_idx].SetDebug (is_debug);
+
+ if (is_debug)
+ {
+ switch (nlist.n_type)
+ {
+ case N_GSYM: // global symbol: name,,NO_SECT,type,0
+ // Sometimes the N_GSYM value contains the address.
+ if (nlist.n_value != 0)
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeGlobal;
+ break;
+
+ case N_FNAME: // procedure name (f77 kludge): name,,NO_SECT,0,0
+ type = eSymbolTypeFunction;
+ break;
+
+ case N_FUN: // procedure: name,,n_sect,linenumber,address
+ if (symbol_name)
+ {
+ type = eSymbolTypeFunction;
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_FUN_indexes.push_back(sym_idx);
+ }
+ else
+ {
+ type = eSymbolTypeFunctionEnd;
+
+ if ( !N_FUN_indexes.empty() )
+ {
+ // Copy the size of the function into the original STAB entry so we don't have
+ // to hunt for it later
+ symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value);
+ N_FUN_indexes.pop_back();
+ // We dont' really need the end function STAB as it contains the size which
+ // we already placed with the original symbol, so don't add it if we want a
+ // minimal symbol table
+ if (minimize)
+ add_nlist = false;
+ }
+ }
+ break;
+
+ case N_STSYM: // static symbol: name,,n_sect,type,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeStatic;
+ break;
+
+ case N_LCSYM: // .lcomm symbol: name,,n_sect,type,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeCommonBlock;
+ break;
+
+ case N_BNSYM:
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ if (minimize)
+ {
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ }
+ else
+ {
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ N_NSYM_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ }
+ break;
+
+ case N_ENSYM:
+ // Set the size of the N_BNSYM to the terminating index of this N_ENSYM
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if (minimize)
+ {
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ }
+ else
+ {
+ if ( !N_NSYM_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_NSYM_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_NSYM_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ }
+ break;
+
+
+ case N_OPT: // emitted with gcc2_compiled and in gcc source
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_RSYM: // register sym: name,,NO_SECT,type,register
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_SLINE: // src line: 0,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ case N_SSYM: // structure elt: name,,NO_SECT,type,struct_offset
+ type = eSymbolTypeVariableType;
+ break;
+
+ case N_SO:
+ type = eSymbolTypeSourceFile;
+ if (symbol_name == NULL)
+ {
+ if (N_SO_index == UINT_MAX)
+ {
+ // Skip the extra blank N_SO entries that happen when the entire
+ // path is contained in the second consecutive N_SO STAB.
+ if (minimize)
+ add_nlist = false;
+ }
+ else
+ {
+ // Set the size of the N_SO to the terminating index of this N_SO
+ // so that we can always skip the entire N_SO if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ }
+ N_NSYM_indexes.clear();
+ N_INCL_indexes.clear();
+ N_BRAC_indexes.clear();
+ N_COMM_indexes.clear();
+ N_FUN_indexes.clear();
+ N_SO_index = UINT_MAX;
+ }
+ else if (symbol_name[0] == '/')
+ {
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_SO_index = sym_idx;
+ }
+ break;
+
+ case N_OSO: // object file name: name,,0,0,st_mtime
+ type = eSymbolTypeObjectFile;
+ break;
+
+ case N_LSYM: // local sym: name,,NO_SECT,type,offset
+ type = eSymbolTypeLocal;
+ break;
+
+ //----------------------------------------------------------------------
+ // INCL scopes
+ //----------------------------------------------------------------------
+ case N_BINCL: // include file beginning: name,,NO_SECT,0,sum
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_INCL_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+ case N_EINCL: // include file end: name,,NO_SECT,0,0
+
+ // Set the size of the N_BINCL to the terminating index of this N_EINCL
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_INCL_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_INCL_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_SOL: // #included file name: name,,n_sect,0,address
+ type = eSymbolTypeHeaderFile;
+ break;
+
+ case N_PARAMS: // compiler parameters: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_VERSION: // compiler version: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_OLEVEL: // compiler -O level: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_PSYM: // parameter: name,,NO_SECT,type,offset
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_ENTRY: // alternate entry: name,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ //----------------------------------------------------------------------
+ // Left and Right Braces
+ //----------------------------------------------------------------------
+ case N_LBRAC: // left bracket: 0,,NO_SECT,nesting level,address
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ N_BRAC_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_RBRAC: // right bracket: 0,,NO_SECT,nesting level,address
+ // Set the size of the N_LBRAC to the terminating index of this N_RBRAC
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ if ( !N_BRAC_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_BRAC_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_EXCL: // deleted include file: name,,NO_SECT,0,sum
+ type = eSymbolTypeHeaderFile;
+ break;
+
+ //----------------------------------------------------------------------
+ // COMM scopes
+ //----------------------------------------------------------------------
+ case N_BCOMM: // begin common: name,,NO_SECT,0,0
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ type = eSymbolTypeScopeBegin;
+ N_COMM_indexes.push_back(sym_idx);
+ break;
+
+ case N_ECOML: // end common (local name): 0,,n_sect,0,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ // Fall through
+
+ case N_ECOMM: // end common: name,,n_sect,0,0
+ // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_COMM_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_COMM_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_LENG: // second stab entry with length information
+ type = eSymbolTypeAdditional;
+ break;
+
+ default: break;
+ }
+ }
+ else
+ {
+ //uint8_t n_pext = N_PEXT & nlist.n_type;
+ uint8_t n_type = N_TYPE & nlist.n_type;
+ sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
+
+ if (symbol_name && ::strstr (symbol_name, ".objc") == symbol_name)
+ {
+ type = eSymbolTypeRuntime;
+ }
+ else
+ {
+ switch (n_type)
+ {
+ case N_INDR: // Fall through
+ case N_PBUD: // Fall through
+ case N_UNDF:
+ type = eSymbolTypeExtern;
+ break;
+
+ case N_ABS:
+ type = eSymbolTypeAbsolute;
+ break;
+
+ case N_SECT:
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+
+ assert(symbol_section != NULL);
+ if (TEXT_eh_frame_sectID == nlist.n_sect)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ uint32_t section_type = symbol_section->GetAllFlagBits() & SECTION_TYPE;
+
+ switch (section_type)
+ {
+ case S_REGULAR: break; // regular section
+ //case S_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section
+ case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings
+ case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination
+ //case S_COALESCED: type = eSymbolType; break; // section contains symbols that are to be coalesced
+ //case S_GB_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section (that can be larger than 4 gigabytes)
+ case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing
+ case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals
+ case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break;
+ default: break;
+ }
+
+ if (type == eSymbolTypeInvalid)
+ {
+ const char *symbol_sect_name = symbol_section->GetName().AsCString();
+ if (symbol_section->IsDescendant (text_section_sp.get()))
+ {
+ if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE | S_ATTR_SOME_INSTRUCTIONS))
+ type = eSymbolTypeData;
+ else
+ type = eSymbolTypeCode;
+ }
+ else
+ if (symbol_section->IsDescendant(data_section_sp.get()))
+ {
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name)
+ {
+ type = eSymbolTypeRuntime;
+ }
+ else
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ type = eSymbolTypeData;
+ }
+ }
+ else
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name)
+ {
+ type = eSymbolTypeTrampoline;
+ }
+ else
+ if (symbol_section->IsDescendant(objc_section_sp.get()))
+ {
+ type = eSymbolTypeRuntime;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (add_nlist)
+ {
+ bool symbol_name_is_mangled = false;
+ if (symbol_name && symbol_name[0] == '_')
+ {
+ symbol_name_is_mangled = symbol_name[1] == '_';
+ symbol_name++; // Skip the leading underscore
+ }
+ uint64_t symbol_value = nlist.n_value;
+ if (symbol_section != NULL)
+ symbol_value -= symbol_section->GetFileAddress();
+
+ sym[sym_idx].SetID (nlist_idx);
+ sym[sym_idx].SetType (type);
+ if (symbol_name)
+ sym[sym_idx].GetMangled().SetValue(symbol_name, symbol_name_is_mangled);
+ sym[sym_idx].GetAddressRangeRef().GetBaseAddress().SetSection (symbol_section);
+ sym[sym_idx].GetAddressRangeRef().GetBaseAddress().SetOffset (symbol_value);
+ sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+
+ ++sym_idx;
+ }
+ else
+ {
+ sym[sym_idx].Clear();
+ }
+
+ }
+
+
+ // STAB N_GSYM entries end up having a symbol type eSymbolTypeGlobal and when the symbol value
+ // is zero, the address of the global ends up being in a non-STAB entry. Try and fix up all
+ // such entries by figuring out what the address for the global is by looking up this non-STAB
+ // entry and copying the value into the debug symbol's value to save us the hassle in the
+ // debug symbol parser.
+
+ Symbol *global_symbol = NULL;
+ for (nlist_idx = 0;
+ nlist_idx < symtab_load_command.nsyms && (global_symbol = symtab->FindSymbolWithType(eSymbolTypeGlobal, nlist_idx)) != NULL;
+ nlist_idx++)
+ {
+ if (global_symbol->GetValue().GetFileAddress() == 0)
+ {
+ std::vector<uint32_t> indexes;
+ if (symtab->AppendSymbolIndexesWithName(global_symbol->GetMangled().GetName(), indexes) > 0)
+ {
+ std::vector<uint32_t>::const_iterator pos;
+ std::vector<uint32_t>::const_iterator end = indexes.end();
+ for (pos = indexes.begin(); pos != end; ++pos)
+ {
+ symbol_ptr = symtab->SymbolAtIndex(*pos);
+ if (symbol_ptr != global_symbol && symbol_ptr->IsDebug() == false)
+ {
+ global_symbol->SetValue(symbol_ptr->GetValue());
+ break;
+ }
+ }
+ }
+ }
+ }
+ // Now synthesize indirect symbols
+ if (m_dysymtab.nindirectsyms != 0)
+ {
+ DataBufferSP indirect_symbol_indexes_sp(m_file.ReadFileContents(m_offset + m_dysymtab.indirectsymoff, m_dysymtab.nindirectsyms * 4));
+
+ if (indirect_symbol_indexes_sp && indirect_symbol_indexes_sp->GetByteSize())
+ {
+ DataExtractor indirect_symbol_index_data (indirect_symbol_indexes_sp, m_data.GetByteOrder(), m_data.GetAddressByteSize());
+
+ for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size(); ++sect_idx)
+ {
+ if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) == S_SYMBOL_STUBS)
+ {
+ uint32_t symbol_stub_byte_size = m_mach_sections[sect_idx].reserved2;
+ if (symbol_stub_byte_size == 0)
+ continue;
+
+ const uint32_t num_symbol_stubs = m_mach_sections[sect_idx].size / symbol_stub_byte_size;
+
+ if (num_symbol_stubs == 0)
+ continue;
+
+ const uint32_t symbol_stub_index_offset = m_mach_sections[sect_idx].reserved1;
+ uint32_t stub_sym_id = symtab_load_command.nsyms;
+ for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs; ++stub_idx)
+ {
+ const uint32_t symbol_stub_index = symbol_stub_index_offset + stub_idx;
+ const lldb::addr_t symbol_stub_addr = m_mach_sections[sect_idx].addr + (stub_idx * symbol_stub_byte_size);
+ uint32_t symbol_stub_offset = symbol_stub_index * 4;
+ if (indirect_symbol_index_data.ValidOffsetForDataOfSize(symbol_stub_offset, 4))
+ {
+ const uint32_t symbol_index = indirect_symbol_index_data.GetU32 (&symbol_stub_offset);
+
+ Symbol *stub_symbol = symtab->SymbolAtIndex(symbol_index);
+ if (stub_symbol)
+ {
+ Address so_addr(symbol_stub_addr, section_list);
+
+ if (stub_symbol->GetType() == eSymbolTypeExtern)
+ {
+ // Change the external symbol into a trampoline that makes sense
+ // These symbols were N_UNDF N_EXT, and are useless to us, so we
+ // can re-use them so we don't have to make up a synthetic symbol
+ // for no good reason.
+ stub_symbol->SetType (eSymbolTypeTrampoline);
+ stub_symbol->SetExternal (false);
+ stub_symbol->GetAddressRangeRef().GetBaseAddress() = so_addr;
+ stub_symbol->GetAddressRangeRef().SetByteSize (symbol_stub_byte_size);
+ }
+ else
+ {
+ // Make a synthetic symbol to describe the trampoline stub
+ if (sym_idx >= num_syms)
+ {
+ sym = symtab->Resize (num_syms + 16);
+ num_syms = symtab->GetNumSymbols();
+ }
+ sym[sym_idx].SetID (stub_sym_id++);
+ sym[sym_idx].GetMangled() = stub_symbol->GetMangled();
+ sym[sym_idx].SetType (eSymbolTypeTrampoline);
+ sym[sym_idx].SetIsSynthetic (true);
+ sym[sym_idx].GetAddressRangeRef().GetBaseAddress() = so_addr;
+ sym[sym_idx].GetAddressRangeRef().SetByteSize (symbol_stub_byte_size);
+ ++sym_idx;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (sym_idx != symtab->GetNumSymbols())
+ symtab->Resize (sym_idx);
+
+ return symtab->GetNumSymbols();
+ }
+ }
+ offset = cmd_offset + symtab_load_command.cmdsize;
+ }
+ return 0;
+}
+
+
+void
+ObjectFileMachO::Dump (Stream *s)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64)
+ s->PutCString("ObjectFileMachO64");
+ else
+ s->PutCString("ObjectFileMachO32");
+
+ ArchSpec header_arch(m_header.cputype, m_header.cpusubtype);
+
+ *s << ", file = '" << m_file << "', arch = " << header_arch.AsCString() << "\n";
+
+ if (m_sections_ap.get())
+ m_sections_ap->Dump(s, NULL, true);
+
+ if (m_symtab_ap.get())
+ m_symtab_ap->Dump(s, NULL);
+}
+
+
+bool
+ObjectFileMachO::GetUUID (UUID* uuid)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ struct uuid_command load_cmd;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_UUID)
+ {
+ const uint8_t *uuid_bytes = m_data.PeekData(offset, 16);
+ if (uuid_bytes)
+ {
+ uuid->SetBytes (uuid_bytes);
+ return true;
+ }
+ return false;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+ return false;
+}
+
+
+uint32_t
+ObjectFileMachO::GetDependentModules (FileSpecList& files)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ struct load_command load_cmd;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t count = 0;
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd)
+ {
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_DYLINKER:
+ case LC_LOADFVMLIB:
+ {
+ uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ const char *path = m_data.PeekCStr(name_offset);
+ // Skip any path that starts with '@' since these are usually:
+ // @executable_path/.../file
+ // @rpath/.../file
+ if (path && path[0] != '@')
+ {
+ FileSpec file_spec(path);
+ if (files.AppendIfUnique(file_spec))
+ count++;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+ return count;
+}
+
+bool
+ObjectFileMachO::GetTargetTriple (ConstString &target_triple)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ std::string triple(GetModule()->GetArchitecture().AsCString());
+ triple += "-apple-darwin";
+ target_triple.SetCString(triple.c_str());
+ if (target_triple)
+ return true;
+ return false;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectFileMachO::GetPluginName()
+{
+ return "ObjectFileMachO";
+}
+
+const char *
+ObjectFileMachO::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileMachO::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectFileMachO::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectFileMachO::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectFileMachO::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
+
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
new file mode 100644
index 0000000..3ffeb24
--- /dev/null
+++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -0,0 +1,131 @@
+//===-- ObjectFileMachO.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_ObjectFileMachO_h_
+#define liblldb_ObjectFileMachO_h_
+
+#include <mach-o/loader.h>
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+//----------------------------------------------------------------------
+// This class needs to be hidden as eventually belongs in a plugin that
+// will export the ObjectFile protocol
+//----------------------------------------------------------------------
+class ObjectFileMachO :
+ public lldb_private::ObjectFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static ObjectFile *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectFileMachO (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectFileMachO();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual size_t
+ GetAddressByteSize () const;
+
+ virtual lldb_private::Symtab *
+ GetSymtab();
+
+ virtual lldb_private::SectionList *
+ GetSectionList();
+
+ virtual void
+ Dump (lldb_private::Stream *s);
+
+ virtual bool
+ GetTargetTriple (lldb_private::ConstString &target_triple);
+
+ virtual bool
+ GetUUID (lldb_private::UUID* uuid);
+
+ virtual uint32_t
+ GetDependentModules (lldb_private::FileSpecList& files);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+
+protected:
+ mutable lldb_private::Mutex m_mutex;
+ struct mach_header m_header;
+ mutable std::auto_ptr<lldb_private::SectionList> m_sections_ap;
+ mutable std::auto_ptr<lldb_private::Symtab> m_symtab_ap;
+
+ struct dysymtab_command m_dysymtab;
+ std::vector<struct segment_command_64> m_mach_segments;
+ std::vector<struct section_64> m_mach_sections;
+
+ size_t
+ ParseSections ();
+
+ size_t
+ ParseSymtab (bool minimize);
+
+};
+
+#endif // liblldb_ObjectFileMachO_h_
diff --git a/source/Plugins/Process/MacOSX-User/scripts/cc-swig b/source/Plugins/Process/MacOSX-User/scripts/cc-swig
new file mode 100644
index 0000000..0bb089a
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/scripts/cc-swig
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+use File::Basename;
+
+sub execute_command
+{
+ print join(' ', @_), "\n";
+ if (scalar(@_) > 0) {
+ system(@_);
+ } else {
+ system($_[0]);
+ }
+}
+
+my $infile = $ENV{SCRIPT_INPUT_FILE_1};
+my($in_basename, $in_dirname, $in_extension) = fileparse($infile, qr/\.[^.]*/);
+my $outdir = "$ENV{DERIVED_FILE_DIR}";
+my $perl_wrap_c = "$outdir/${in_basename}_perl_wrap.c";
+mkdir "$ENV{OBJECT_FILE_DIR}";
+my $perl_wrap_o = "$ENV{OBJECT_FILE_DIR}/${in_basename}_perl_wrap.o";
+my $perl_module = "$outdir/${in_basename}.pm";
+my $header_paths = "-I'../../../../../debugcore/source' -I'../../../../../DebugBase'";
+my $framework_opts = "-F'$ENV{CONFIGURATION_BUILD_DIR}' ";
+execute_command("/usr/bin/swig -shadow -perl5 -DHAS_BOOL $header_paths -outdir '$outdir' -o '$perl_wrap_c' '$infile'");
+
+# Get any needed perl options for the next compile
+my $ccopts = `perl -MExtUtils::Embed -e ccopts`;
+my $libperl_dir = undef;
+if ($ccopts =~ /-I(\/System.*CORE)/)
+{
+ $libperl_dir = $1;
+ print "libperl directory: '$libperl_dir'\n";
+}
+
+execute_command("cd '$ENV{OBJECT_FILE_DIR}' && ln -s '$libperl_dir/libperl.dylib'");
+
+
+# Strip out the default architectures it gave us, we will add them back with
+# the $arch_opts below
+$ccopts =~ s/-arch [a-z_0-9]+//g;
+
+# Get a list of our build architectures
+my $arch_opts = "-arch " . join(' -arch ', split('\s+', $ENV{ARCHS}));
+
+execute_command("gcc -c -Dbool=char $arch_opts $ccopts $header_paths $framework_opts -I'$ENV{PROJECT_DIR}/source' '$perl_wrap_c' -o '$perl_wrap_o'");
+
+execute_command("cp '$perl_module' '$ENV{CONFIGURATION_BUILD_DIR}/$ENV{SHARED_SUPPORT_FOLDER_PATH}'");
\ No newline at end of file
diff --git a/source/Plugins/Process/MacOSX-User/scripts/config.pl b/source/Plugins/Process/MacOSX-User/scripts/config.pl
new file mode 100644
index 0000000..a6cf6ce
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/scripts/config.pl
@@ -0,0 +1,71 @@
+#!/usr/bin/perl
+
+use strict;
+my $config_file = "$ENV{SCRIPT_OUTPUT_FILE_0}";
+
+# Define the tests we need to run during this configuration
+my @config_tests = (
+ {
+ NAME => "HAVE_64_BIT_MACH_EXCEPTIONS",
+ TEST => "-e '$ENV{SDKROOT}/usr/include/mach/mach_exc.defs'",
+ COMMENT => "// Defined if we can use 64 bit mach exceptions",
+ FAIL => "#undef HAVE_64_BIT_MACH_EXCEPTIONS\
+#define mach_exception_data_t exception_data_t\
+#define mach_exception_data_type_t exception_data_type_t\
+#define mach_exc_server exc_server\
+#define MACH_EXCEPTION_CODES 0\n",
+ SUCCESS => "#define HAVE_64_BIT_MACH_EXCEPTIONS 1\n",
+ }
+);
+
+#----------------------------------------------------------------------
+# Open the config file
+#----------------------------------------------------------------------
+open(CONFIG, "> $config_file") || die "Couldn't open '$config_file' for writing: $!\n";
+print CONFIG "/*" . "-" x 72 . "\n";
+print CONFIG "// This file is auto generated by a config.pl, do not edit by hand!\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// COMMAND LINE\n";
+print CONFIG "// " . join(' ', @ARGV) . "\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// ENVIRONMENT\n";
+my $key;
+my $val;
+while (($key, $val) = each %ENV)
+{
+ printf CONFIG "// %s = %s\n", $key, $val;
+}
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// SETTINGS\n";
+print CONFIG "// config_file: '$config_file'\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "*/\n\n";
+print CONFIG "#ifndef liblldb_PDConfig_h_\n";
+print CONFIG "#define liblldb_PDConfig_h_\n";
+
+
+#----------------------------------------------------------------------
+# Run the tests
+#----------------------------------------------------------------------
+foreach my $test_href (@config_tests)
+{
+ if (exists $test_href->{COMMENT}) {
+ print CONFIG "\n$test_href->{COMMENT}\n";
+ } else {
+ print CONFIG "\n// $test_href->{NAME}\n";
+ }
+
+ my $test_result = eval "$test_href->{TEST}";
+ if ($test_result != 0)
+ {
+ print CONFIG "$test_href->{SUCCESS}\n";
+ }
+ else
+ {
+ print CONFIG "$test_href->{FAIL}\n";
+ }
+}
+
+print CONFIG "#endif // #ifndef liblldb_PDConfig_h_\n";
+close(CONFIG);
+
diff --git a/source/Plugins/Process/MacOSX-User/scripts/test-ProcessDebug.pl b/source/Plugins/Process/MacOSX-User/scripts/test-ProcessDebug.pl
new file mode 100755
index 0000000..96b3115
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/scripts/test-ProcessDebug.pl
@@ -0,0 +1,409 @@
+#!/usr/bin/perl
+
+use strict;
+use Cwd 'abs_path';
+our $home = $ENV{HOME} || die "ERROR: Couldn't deduce your home directory...\n";
+
+our @inc_paths = (
+ './include',
+);
+
+my $inc_paths_added = 0;
+foreach my $inc_path (@inc_paths)
+{
+ if (-e $inc_path)
+ {
+ push (@INC, abs_path($inc_path));
+ $inc_paths_added++;
+ }
+}
+
+if ($inc_paths_added == 0)
+{
+ die "Please compile the Release version of lldb\n";
+}
+
+require lldb;
+
+# my $state = lldb::eStateAttaching;
+
+use constant UINT32_MAX => 4294967295;
+
+#----------------------------------------------------------------------
+# Interactive Commands
+#----------------------------------------------------------------------
+our %commands = (
+ break => {
+ name => 'break', # in case an alias is used to get to this command
+ description => "Sets a breakpoint.",
+ usage => ["break ADDR"],
+ function => \&command_set_breakpoint,
+ runs_target => 0,
+ },
+ delete => {
+ name => 'delete', # in case an alias is used to get to this command
+ description => "Deletes one or more breakpoints by ID.\
+If no breakpoint IDs are given all breakpoints will be deleted.\
+If one or more IDs are given, only those breakpoints will be deleted.",
+ usage => ["delete [ID1 ID2 ...]"],
+ function => \&command_clear_breakpoint,
+ runs_target => 0,
+ },
+ continue => {
+ name => 'continue', # in case an alias is used to get to this command
+ description => "Continues target execution.",
+ usage => ["continue [ADDR]"],
+ function => \&command_continue,
+ runs_target => 1
+ },
+ step => {
+ name => 'step', # in case an alias is used to get to this command
+ description => "Single steps one instruction.",
+ usage => ["step"],
+ function => \&command_step,
+ runs_target => 1
+ },
+ info => {
+ name => 'info', # in case an alias is used to get to this command
+ description => "Gets info on a variety of things.",
+ usage => ["info reg", "info thread", "info threads"],
+ function => \&command_info,
+ runs_target => 0
+ },
+ help => {
+ name => 'help', # in case an alias is used to get to this command
+ description => "Displays a list of all commands, or help for a specific command.",
+ usage => ["help", "help CMD"],
+ function => \&command_help,
+ runs_target => 0
+ }
+);
+
+#----------------------------------------------------------------------
+# Command aliases
+#----------------------------------------------------------------------
+our %aliases = (
+ b => $commands{break},
+ c => $commands{continue},
+ s => $commands{step},
+ d => $commands{delete},
+ h => $commands{help}
+);
+
+our $opt_g = 0; # Enable verbose debug logging
+our $opt_v = 0; # Verbose mode
+my $prev_command_href = undef;
+my $stdio = '/dev/stdin';
+my $launch = 0;
+my @env = ();
+my @break_ids;
+
+#----------------------------------------------------------------------
+# Given a command string, return the command hash reference for it, or
+# undef if it doesn't exist.
+#----------------------------------------------------------------------
+sub get_command_hash_ref
+{
+ my $cmd = shift;
+ my $cmd_href = undef;
+ if (length($cmd) == 0) { $cmd_href = $prev_command_href; }
+ elsif (exists $aliases{$cmd}) { $cmd_href = $aliases{$cmd}; }
+ elsif (exists $commands{$cmd}) { $cmd_href = $commands{$cmd}; }
+ defined $cmd_href and $prev_command_href = $cmd_href;
+ return $cmd_href;
+}
+
+#----------------------------------------------------------------------
+# Set a breakpoint
+#----------------------------------------------------------------------
+sub command_set_breakpoint
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_set_breakpoint (pid = $pid, locations = @_)\n";
+ foreach my $location (@_)
+ {
+ my $success = 0;
+ my $address = hex($location);
+ if ($address != 0)
+ {
+ my $break_id = lldb::PDBreakpointSet ($pid, $address, 1, 0);
+ if ($break_id != $lldb::PD_INVALID_BREAK_ID)
+ {
+ printf("Breakpoint %i is set.\n", $break_id);
+ push(@break_ids, $break_id);
+ $success = 1;
+ }
+ }
+ $success or print("error: failed to set breakpoint at $location.\n");
+ }
+ return 1;
+}
+
+#----------------------------------------------------------------------
+# Clear a breakpoint
+#----------------------------------------------------------------------
+sub command_clear_breakpoint
+{
+ my $pid = shift;
+ my $tid = shift;
+ if (@_)
+ {
+ my $break_id;
+ my @cleared_break_ids;
+ my @new_break_ids;
+ $opt_g and print "command_clear_breakpoint (pid = $pid, break_ids = @_)\n";
+ foreach $break_id (@_)
+ {
+ if (lldb::PDBreakpointClear ($pid, $break_id))
+ {
+ printf("Breakpoint %i has been cleared.\n", $break_id);
+ push (@cleared_break_ids, $break_id);
+ }
+ else
+ {
+ printf("error: failed to clear breakpoint %i.\n", $break_id);
+ }
+ }
+
+ foreach my $old_break_id (@break_ids)
+ {
+ my $found_break_id = 0;
+ foreach $break_id (@cleared_break_ids)
+ {
+ if ($old_break_id == $break_id)
+ {
+ $found_break_id = 1;
+ }
+ }
+ $found_break_id or push (@new_break_ids, $old_break_id);
+ }
+ @break_ids = @new_break_ids;
+ }
+ else
+ {
+ # Nothing specified, clear all breakpoints
+ return command_clear_breakpoint($pid, $tid, @break_ids);
+ }
+ return 1;
+}
+#----------------------------------------------------------------------
+# Continue program execution
+#----------------------------------------------------------------------
+sub command_continue
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_continue (pid = $pid)\n";
+ if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+ {
+ $opt_v and printf("Resuming pid %d...\n", $pid);
+ return lldb::PDProcessResume ($pid);
+ }
+ return 0;
+}
+
+sub command_step
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_step (pid = $pid, tid = $tid)\n";
+ if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+ {
+ $opt_v and printf("Single stepping pid %d tid = %4.4x...\n", $pid, $tid);
+ return lldb::PDThreadResume ($pid, $tid, 1);
+ }
+ return 0;
+}
+
+sub command_info
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_step (pid = $pid, tid = $tid)\n";
+ if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+ {
+ if (@_)
+ {
+ my $info_cmd = shift;
+ if ($info_cmd eq 'reg')
+ {
+
+ }
+ elsif ($info_cmd eq 'thread')
+ {
+ # info on the current thread
+ printf("thread 0x%4.4x %s\n", $tid, lldb::PDThreadGetInfo($pid, $tid));
+ }
+ elsif ($info_cmd eq 'threads')
+ {
+ my $num_threads = lldb::PDProcessGetNumThreads( $pid );
+ for my $thread_num (1..$num_threads)
+ {
+ my $curr_tid = lldb::PDProcessGetThreadAtIndex ( $pid, $thread_num - 1 );
+ printf("%c%u - thread 0x%4.4x %s\n", $curr_tid == $tid ? '*' : ' ', $thread_num, $curr_tid, lldb::PDThreadGetInfo($pid, $curr_tid));
+ }
+ }
+ }
+ }
+ return 1;
+}
+#----------------------------------------------------------------------
+# Get help on all commands, or a specific list of commands
+#----------------------------------------------------------------------
+sub command_help
+{
+ my $pid = shift;
+ my $tid = shift;
+ if (@_)
+ {
+ $opt_g and print "command_continue (pid = $pid, commands = @_)\n";
+ foreach my $cmd (@_)
+ {
+ my $cmd_href = get_command_hash_ref($cmd);
+ if ($cmd_href)
+ {
+ print '#', '-' x 72, "\n# $cmd_href->{name}\n", '#', '-' x 72, "\n";
+ my $usage_aref = $cmd_href->{usage};
+ if (@{$usage_aref})
+ {
+ print " USAGE\n";
+ foreach my $usage (@{$usage_aref}) {
+ print " $usage\n";
+ }
+ print "\n";
+ }
+ print " DESCRIPTION\n $cmd_href->{description}\n\n";
+ }
+ else
+ {
+ print " invalid command: '$cmd'\n\n";
+ }
+ }
+ }
+ else
+ {
+ return command_help($pid, sort keys %commands);
+ }
+ return 1;
+}
+
+
+#lldb::PDLogSetLogMask ($lldb::PD_LOG_ALL);
+#lldb::PDLogSetLogFile ('/dev/stdout');
+
+print "running: ", join(' ', @ARGV), "\n";
+
+my $pid = lldb::PDProcessLaunch ($ARGV[0], \@ARGV, \@env, "i386", '/dev/stdin', '/dev/stdout', '/dev/stderr', $launch, '', 0);
+my $pid_state;
+while ($pid)
+{
+ $opt_g and printf("PDProcessWaitForEvents (%d, 0x%4.4x, SET, 1)\n", $pid, $lldb::PD_ALL_EVENTS);
+ my $events = lldb::PDProcessWaitForEvents ($pid, $lldb::PD_ALL_EVENTS, 1, 1);
+ if ($events)
+ {
+ $opt_g and printf ("Got event: 0x%8.8x\n", $events);
+
+ if ($events & $lldb::PD_EVENT_IMAGES_CHANGED)
+ {
+ $opt_g and printf("pid %d images changed...\n", $pid);
+ }
+
+ if ($events & $lldb::PD_EVENT_STDIO)
+ {
+ $opt_g and printf("pid %d has stdio...\n", $pid);
+ }
+
+ if ($events & $lldb::PD_EVENT_ASYNC_INTERRUPT)
+ {
+ $opt_g and printf("pid %d got async interrupt...\n", $pid);
+ }
+
+ if ($events & $lldb::PD_EVENT_RUNNING)
+ {
+ $pid_state = lldb::PDProcessGetState ($pid);
+ $opt_v and printf( "pid %d state: %s.\n", $pid, lldb::PDStateAsString ($pid_state) );
+ }
+
+ if ($events & $lldb::PD_EVENT_STOPPED)
+ {
+ $pid_state = lldb::PDProcessGetState ($pid);
+ $opt_v and printf( "pid %d state: %s.\n", $pid, lldb::PDStateAsString ($pid_state) );
+
+ if ($pid_state == $lldb::eStateUnloaded ||
+ $pid_state == $lldb::eStateAttaching ||
+ $pid_state == $lldb::eStateLaunching )
+ {
+
+ }
+ elsif ( $pid_state == $lldb::eStateStopped )
+ {
+ my $tid = lldb::PDProcessGetCurrentThread ( $pid );
+ my $pc = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "eip", 0);
+ $pc != 0 and printf("pc = 0x%8.8x ", $pc);
+ # my $sp = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "esp", 0);
+ # $sp != 0 and printf("sp = 0x%8.8x ", $sp);
+ # my $fp = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "ebp", 0);
+ # $sp != 0 and printf("fp = 0x%8.8x ", $fp);
+ # print "\n";
+ my $done = 0;
+ my $input;
+ while (!$done)
+ {
+ print '(pdbg) ';
+
+ chomp($input = <STDIN>);
+ my @argv = split(/\s+/, $input);
+ my $cmd = @argv ? shift @argv : undef;
+ my $cmd_href = get_command_hash_ref ($cmd);
+ if ($cmd_href)
+ {
+ # Print the expanded alias if one was used
+ if ($opt_v and $cmd_href->{name} ne $cmd)
+ {
+ print "$cmd_href->{name} @argv\n";
+ }
+
+ # Call the command's callback function to make things happen
+ if ($cmd_href->{function}($pid, $tid, @argv))
+ {
+ $done = $cmd_href->{runs_target};
+ }
+ }
+ else
+ {
+ print "invalid command: '$cmd'\nType 'help' for a list of all commands.\nType 'help CMD' for help on a specific commmand.\n";
+ }
+ }
+ }
+ elsif ( $pid_state == $lldb::eStateRunning ||
+ $pid_state == $lldb::eStateStepping )
+ {
+
+ }
+ elsif ( $pid_state == $lldb::eStateCrashed ||
+ $pid_state == $lldb::eStateDetached ||
+ $pid_state == $lldb::eStateExited )
+ {
+ $pid = 0;
+ }
+ elsif ( $pid_state == $lldb::eStateSuspended )
+ {
+ }
+ else
+ {
+ }
+ }
+
+ if ($pid)
+ {
+ $opt_g and printf("PDProcessResetEvents(%d, 0x%8.8x)\n", $pid, $events);
+ lldb::PDProcessResetEvents($pid, $events);
+ }
+ }
+}
+
+if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+{
+ lldb::PDProcessDetach ($pid);
+}
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.cpp b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.cpp
new file mode 100644
index 0000000..7dc8d2c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.cpp
@@ -0,0 +1,575 @@
+//===-- MachException.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+
+#include "MachException.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb_private;
+
+// Routine mach_exception_raise
+extern "C"
+kern_return_t catch_mach_exception_raise
+(
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt
+);
+
+extern "C"
+kern_return_t catch_mach_exception_raise_state
+(
+ mach_port_t exception_port,
+ exception_type_t exception,
+ const mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ const thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+);
+
+// Routine mach_exception_raise_state_identity
+extern "C"
+kern_return_t catch_mach_exception_raise_state_identity
+(
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+);
+
+extern "C" boolean_t mach_exc_server(
+ mach_msg_header_t *InHeadP,
+ mach_msg_header_t *OutHeadP);
+
+// Any access to the g_message variable should be done by locking the
+// g_message_mutex first, using the g_message variable, then unlocking
+// the g_message_mutex. See MachException::Message::CatchExceptionRaise()
+// for sample code.
+
+static MachException::Data *g_message = NULL;
+//static pthread_mutex_t g_message_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise_state
+(
+ mach_port_t exc_port,
+ exception_type_t exc_type,
+ const mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count,
+ int * flavor,
+ const thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t * new_stateCnt
+)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ {
+ log->Printf("::%s ( exc_port = 0x%4.4x, exc_type = %d ( %s ), exc_data = " MACH_EXCEPTION_DATA_FMT_HEX ", exc_data_count = %d)",
+ __FUNCTION__,
+ exc_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data,
+ exc_data_count);
+ }
+ return KERN_FAILURE;
+}
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise_state_identity
+(
+ mach_port_t exc_port,
+ mach_port_t thread_port,
+ mach_port_t task_port,
+ exception_type_t exc_type,
+ mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count,
+ int * flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+)
+{
+ kern_return_t kret;
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ {
+ log->Printf("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
+ __FUNCTION__,
+ exc_port,
+ thread_port,
+ task_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data_count,
+ exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
+ exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
+ }
+ kret = mach_port_deallocate (mach_task_self (), task_port);
+ kret = mach_port_deallocate (mach_task_self (), thread_port);
+
+ return KERN_FAILURE;
+}
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise
+(
+ mach_port_t exc_port,
+ mach_port_t thread_port,
+ mach_port_t task_port,
+ exception_type_t exc_type,
+ mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count)
+{
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ {
+ log->Printf("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
+ __FUNCTION__,
+ exc_port,
+ thread_port,
+ task_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data_count,
+ exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
+ exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
+ }
+
+ g_message->task_port = task_port;
+ g_message->thread_port = thread_port;
+ g_message->exc_type = exc_type;
+ g_message->exc_data.resize(exc_data_count);
+ ::memcpy (&g_message->exc_data[0], exc_data, g_message->exc_data.size() * sizeof (mach_exception_data_type_t));
+ return KERN_SUCCESS;
+}
+
+
+void
+MachException::Message::PutToLog(Log *log) const
+{
+ if (log)
+ {
+ log->Printf(" exc_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx } ",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id);
+
+ log->Printf( "reply_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx }",
+ reply_msg.hdr.msgh_bits,
+ reply_msg.hdr.msgh_size,
+ reply_msg.hdr.msgh_remote_port,
+ reply_msg.hdr.msgh_local_port,
+ reply_msg.hdr.msgh_reserved,
+ reply_msg.hdr.msgh_id);
+ state.PutToLog(log);
+ }
+}
+
+bool
+MachException::Data::GetStopInfo(Thread::StopInfo *stop_info) const
+{
+ // Zero out the structure.
+ stop_info->Clear();
+
+ // Make sure we have a valid exception before we return anything valid
+ if (exc_type == 0)
+ return true;
+ // We always stop with a mach exceptions
+ const size_t exc_data_count = exc_data.size();
+ stop_info->SetStopReasonWithException(exc_type, exc_data_count);
+
+ // Fill in a text description
+ const char * exc_name = MachException::Name(exc_type);
+ StreamString sstr;
+ if (exc_name)
+ sstr.PutCString(exc_name);
+ else
+ sstr.Printf ("%i", exc_type);
+
+ int signal = SoftSignal();
+ if (signal > 0)
+ {
+ const char *sig_str = Host::GetSignalAsCString(signal);
+ if (sig_str)
+ sstr.Printf (" EXC_SOFT_SIGNAL(%s)", sig_str);
+ else
+ sstr.Printf (" EXC_SOFT_SIGNAL(%i)", signal);
+ }
+ else
+ {
+ // No special disassembly for exception data, just
+ sstr.Printf (" data[%zu] = {", exc_data_count);
+
+ for (size_t idx = 0; idx < exc_data_count; ++idx)
+ sstr.Printf (MACH_EXCEPTION_DATA_FMT_MINHEX "%s", exc_data[idx], ((idx + 1 == exc_data_count) ? "" : ","));
+
+ sstr.PutChar('}');
+ }
+
+ stop_info->SetStopDescription (sstr.GetData());
+
+ // Copy the exception data
+ size_t i;
+ for (i=0; i<exc_data_count; i++)
+ stop_info->SetExceptionDataAtIndex(i, exc_data[i]);
+
+ return true;
+}
+
+
+void
+MachException::Data::DumpStopReason() const
+{
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet();
+ if (log)
+ {
+ int signal = SoftSignal();
+ if (signal > 0)
+ {
+ const char *signal_str = Host::GetSignalAsCString(signal);
+ if (signal_str)
+ log->Printf ("signal(%s)", signal_str);
+ else
+ log->Printf ("signal(%i)", signal);
+ return;
+ }
+ log->Printf ("%s", Name(exc_type));
+ }
+}
+
+kern_return_t
+MachException::Message::Receive(mach_port_t port, mach_msg_option_t options, mach_msg_timeout_t timeout, mach_port_t notify_port)
+{
+ Error err;
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ mach_msg_timeout_t mach_msg_timeout = options & MACH_RCV_TIMEOUT ? timeout : 0;
+ if (log && ((options & MACH_RCV_TIMEOUT) == 0))
+ {
+ // Dump this log message if we have no timeout in case it never returns
+ log->Printf ("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id,
+ options,
+ 0,
+ sizeof (exc_msg.data),
+ port,
+ mach_msg_timeout,
+ notify_port);
+ }
+
+ err = ::mach_msg (&exc_msg.hdr,
+ options, // options
+ 0, // Send size
+ sizeof (exc_msg.data), // Receive size
+ port, // exception port to watch for exception on
+ mach_msg_timeout, // timeout in msec (obeyed only if MACH_RCV_TIMEOUT is ORed into the options parameter)
+ notify_port);
+
+ // Dump any errors we get
+ if (log && err.GetError() != MACH_RCV_TIMED_OUT)
+ {
+ log->Error("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id,
+ options,
+ 0,
+ sizeof (exc_msg.data),
+ port,
+ mach_msg_timeout,
+ notify_port);
+ }
+ return err.GetError();
+}
+
+bool
+MachException::Message::CatchExceptionRaise()
+{
+ bool success = false;
+ // locker will keep a mutex locked until it goes out of scope
+// Mutex::Locker locker(&g_message_mutex);
+ // log->Printf ("calling mach_exc_server");
+ g_message = &state;
+ // The exc_server function is the MIG generated server handling function
+ // to handle messages from the kernel relating to the occurrence of an
+ // exception in a thread. Such messages are delivered to the exception port
+ // set via thread_set_exception_ports or task_set_exception_ports. When an
+ // exception occurs in a thread, the thread sends an exception message to
+ // its exception port, blocking in the kernel waiting for the receipt of a
+ // reply. The exc_server function performs all necessary argument handling
+ // for this kernel message and calls catch_exception_raise,
+ // catch_exception_raise_state or catch_exception_raise_state_identity,
+ // which should handle the exception. If the called routine returns
+ // KERN_SUCCESS, a reply message will be sent, allowing the thread to
+ // continue from the point of the exception; otherwise, no reply message
+ // is sent and the called routine must have dealt with the exception
+ // thread directly.
+ if (mach_exc_server (&exc_msg.hdr, &reply_msg.hdr))
+ {
+ success = true;
+ }
+ else
+ {
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ log->Printf ("mach_exc_server returned zero...");
+ }
+ g_message = NULL;
+ return success;
+}
+
+
+
+kern_return_t
+MachException::Message::Reply(task_t task, pid_t pid, int signal)
+{
+ // Reply to the exception...
+ Error err;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet();
+ if (log)
+ log->Printf("MachException::Message::Reply (task = 0x%4.4x, pid = %i, signal = %i)", task, pid, signal);
+
+ // If we had a soft signal, we need to update the thread first so it can
+ // continue without signaling
+ int soft_signal = state.SoftSignal();
+ int state_pid = LLDB_INVALID_PROCESS_ID;
+ if (task == state.task_port)
+ {
+ // This is our task, so we can update the signal to send to it
+ state_pid = pid;
+ }
+ else
+ {
+ err = ::pid_for_task(state.task_port, &state_pid);
+ }
+
+ if (signal == LLDB_INVALID_SIGNAL_NUMBER)
+ signal = 0;
+
+ if (log)
+ log->Printf("MachException::Message::Reply () updating thread signal to %i (original soft_signal = %i)", signal, soft_signal);
+
+ if (state_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ errno = 0;
+ if (::ptrace (PT_THUPDATE, state_pid, (caddr_t)state.thread_port, signal) != 0)
+ {
+ if (soft_signal != LLDB_INVALID_SIGNAL_NUMBER)
+ // We know we currently can't forward signals for threads that didn't stop in EXC_SOFT_SIGNAL...
+ // So only report it as an error if we should have been able to do it.
+ err.SetErrorToErrno();
+ else
+ err.Clear();
+ }
+ else
+ err.Clear();
+
+ if (log && log->GetMask().IsSet(PD_LOG_EXCEPTIONS) || err.Fail())
+ err.PutToLog(log, "::ptrace (request = PT_THUPDATE, pid = %i, tid = 0x%4.4x, signal = %i)", state_pid, state.thread_port, signal);
+ }
+
+ err = ::mach_msg ( &reply_msg.hdr,
+ MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ reply_msg.hdr.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ if (log)
+ log->LogIf (PD_LOG_EXCEPTIONS, "::mach_msg ( msg->{bits = %#x, size = %u, remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x) = 0x%8.8x",
+ reply_msg.hdr.msgh_bits,
+ reply_msg.hdr.msgh_size,
+ reply_msg.hdr.msgh_remote_port,
+ reply_msg.hdr.msgh_local_port,
+ reply_msg.hdr.msgh_reserved,
+ reply_msg.hdr.msgh_id,
+ MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ reply_msg.hdr.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL,
+ err.GetError());
+
+
+ if (err.Fail())
+ {
+ if (err.GetError() == MACH_SEND_INTERRUPTED)
+ {
+ err.PutToLog(log, "::mach_msg() - send interrupted");
+ }
+ else
+ {
+ if (state.task_port == task)
+ {
+ err.PutToLog(log, "::mach_msg() - failed (task)");
+ abort ();
+ }
+ else
+ {
+ err.PutToLog(log, "::mach_msg() - failed (child of task)");
+ }
+ }
+ }
+
+ return err.GetError();
+}
+
+
+void
+MachException::Data::PutToLog(Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ const char *exc_type_name = MachException::Name(exc_type);
+
+ log->Printf (" state { task_port = 0x%4.4x, thread_port = 0x%4.4x, exc_type = %i (%s) ...", task_port, thread_port, exc_type, exc_type_name ? exc_type_name : "???");
+
+ const size_t exc_data_count = exc_data.size();
+ // Dump any special exception data contents
+ int soft_signal = SoftSignal();
+ if (soft_signal > 0)
+ {
+ const char *sig_str = Host::GetSignalAsCString(soft_signal);
+ log->Printf (" exc_data: EXC_SOFT_SIGNAL (%i (%s))", soft_signal, sig_str ? sig_str : "unknown signal");
+ }
+ else
+ {
+ // No special disassembly for this data, just dump the data
+ size_t idx;
+ for (idx = 0; idx < exc_data_count; ++idx)
+ {
+ log->Printf(" exc_data[%u]: " MACH_EXCEPTION_DATA_FMT_HEX, idx, exc_data[idx]);
+ }
+ }
+}
+
+
+MachException::PortInfo::PortInfo() :
+ count(0)
+{
+ ::bzero (masks, sizeof(masks));
+ ::bzero (ports, sizeof(ports));
+ ::bzero (behaviors, sizeof(behaviors));
+ ::bzero (flavors, sizeof(flavors));
+}
+
+
+kern_return_t
+MachException::PortInfo::Save (task_t task)
+{
+ count = EXC_TYPES_COUNT;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+ if (log)
+ log->Printf ("MachException::PortInfo::Save (task = 0x%4.4x)", task);
+ Error err;
+ if (log)
+ log->Printf("::task_get_exception_ports (task=0x%4.4x, mask=0x%x, maskCnt<=>%u, ports, behaviors, flavors)...", task, EXC_MASK_ALL, count);
+ err = ::task_get_exception_ports (task, EXC_MASK_ALL, masks, &count, ports, behaviors, flavors);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_get_exception_ports (task=0x%4.4x, mask=0x%x, maskCnt<=>%u, ports, behaviors, flavors)", task, EXC_MASK_ALL, count);
+ if (log)
+ {
+ mach_msg_type_number_t i;
+ log->Printf("Index Mask Port Behavior Flavor", masks[i], ports[i], behaviors[i], flavors[i]);
+ log->Printf("===== -------- -------- -------- --------");
+ for (i=0; i<count; ++i)
+ log->Printf("[%3u] %8.8x %8.8x %8.8x %8.8x", i, masks[i], ports[i], behaviors[i], flavors[i]);
+ }
+ if (err.Fail())
+ count = 0;
+ return err.GetError();
+}
+
+kern_return_t
+MachException::PortInfo::Restore (task_t task)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf("MachException::PortInfo::Restore (task = 0x%4.4x)", task);
+ uint32_t i = 0;
+ Error err;
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ err = ::task_set_exception_ports (task, masks[i], ports[i], behaviors[i], flavors[i]);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_set_exception_ports ( task = 0x%4.4x, exception_mask = 0x%8.8x, new_port = 0x%4.4x, behavior = 0x%8.8x, new_flavor = 0x%8.8x )", task, masks[i], ports[i], behaviors[i], flavors[i]);
+
+ if (err.Fail())
+ break;
+ }
+ }
+ count = 0;
+ return err.GetError();
+}
+
+const char *
+MachException::Name(exception_type_t exc_type)
+{
+ switch (exc_type)
+ {
+ case EXC_BAD_ACCESS: return "EXC_BAD_ACCESS";
+ case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION";
+ case EXC_ARITHMETIC: return "EXC_ARITHMETIC";
+ case EXC_EMULATION: return "EXC_EMULATION";
+ case EXC_SOFTWARE: return "EXC_SOFTWARE";
+ case EXC_BREAKPOINT: return "EXC_BREAKPOINT";
+ case EXC_SYSCALL: return "EXC_SYSCALL";
+ case EXC_MACH_SYSCALL: return "EXC_MACH_SYSCALL";
+ case EXC_RPC_ALERT: return "EXC_RPC_ALERT";
+#ifdef EXC_CRASH
+ case EXC_CRASH: return "EXC_CRASH";
+#endif
+ default:
+ break;
+ }
+ return NULL;
+}
+
+
+
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.h
new file mode 100644
index 0000000..1f3aeb0
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.h
@@ -0,0 +1,148 @@
+//===-- MachException.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_MachException_h_
+#define liblldb_MachException_h_
+
+#include <mach/mach.h>
+#include <vector>
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Thread.h"
+// TODO: Get the config script to run to this plug-in
+//#include "PDConfig.h"
+#define HAVE_64_BIT_MACH_EXCEPTIONS // REMOVE THIS WHEN PDConfig.h is included above
+#ifdef HAVE_64_BIT_MACH_EXCEPTIONS
+
+#define MACH_EXCEPTION_DATA_FMT_DEC "%lld"
+#define MACH_EXCEPTION_DATA_FMT_HEX "0x%16.16llx"
+#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%llx"
+
+#else
+
+#define MACH_EXCEPTION_DATA_FMT_DEC "%d"
+#define MACH_EXCEPTION_DATA_FMT_HEX "0x%8.8x"
+#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%x"
+
+#endif
+
+class MachProcess;
+
+typedef union MachMessageTag
+{
+ mach_msg_header_t hdr;
+ char data[1024];
+} MachMessage;
+
+
+class MachException
+{
+public:
+
+ struct PortInfo
+ {
+ exception_mask_t masks[EXC_TYPES_COUNT];
+ mach_port_t ports[EXC_TYPES_COUNT];
+ exception_behavior_t behaviors[EXC_TYPES_COUNT];
+ thread_state_flavor_t flavors[EXC_TYPES_COUNT];
+ mach_msg_type_number_t count;
+
+ PortInfo();
+ kern_return_t Save(task_t task);
+ kern_return_t Restore(task_t task);
+ };
+
+ struct Data
+ {
+ task_t task_port;
+ lldb::tid_t thread_port;
+ exception_type_t exc_type;
+ std::vector<mach_exception_data_type_t> exc_data;
+ Data() :
+ task_port(TASK_NULL),
+ thread_port(THREAD_NULL),
+ exc_type(0),
+ exc_data()
+ {
+ }
+
+ void Clear()
+ {
+ task_port = TASK_NULL;
+ thread_port = THREAD_NULL;
+ exc_type = 0;
+ exc_data.clear();
+ }
+ bool IsValid() const
+ {
+ return task_port != TASK_NULL &&
+ thread_port != THREAD_NULL &&
+ exc_type != 0;
+ }
+ // Return the SoftSignal for this MachException data, or zero if there is none
+ int SoftSignal() const
+ {
+ if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && exc_data[0] == EXC_SOFT_SIGNAL)
+ return exc_data[1];
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ }
+ bool IsBreakpoint() const
+ {
+ return (exc_type == EXC_BREAKPOINT) || ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1);
+ }
+ void PutToLog(lldb_private::Log *log) const;
+ void DumpStopReason() const;
+ bool GetStopInfo(lldb_private::Thread::StopInfo *stop_info) const;
+ };
+
+ struct Message
+ {
+ MachMessage exc_msg;
+ MachMessage reply_msg;
+ Data state;
+
+ Message() :
+ exc_msg(),
+ reply_msg(),
+ state()
+ {
+ memset(&exc_msg, 0, sizeof(exc_msg));
+ memset(&reply_msg, 0, sizeof(reply_msg));
+ }
+ bool CatchExceptionRaise();
+ void PutToLog(lldb_private::Log *log) const;
+ kern_return_t Reply (task_t task, pid_t pid, int signal);
+ kern_return_t Receive( mach_port_t receive_port,
+ mach_msg_option_t options,
+ mach_msg_timeout_t timeout,
+ mach_port_t notify_port = MACH_PORT_NULL);
+
+ typedef std::vector<Message> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ enum
+ {
+ e_actionForward, // Forward signal to inferior process
+ e_actionStop, // Stop when this signal is received
+ };
+ struct Action
+ {
+ task_t task_port; // Set to TASK_NULL for any TASK
+ lldb::tid_t thread_port; // Set to THREAD_NULL for any thread
+ exception_type_t exc_mask; // Mach exception mask to watch for
+ std::vector<mach_exception_data_type_t> exc_data_mask; // Mask to apply to exception data, or empty to ignore exc_data value for exception
+ std::vector<mach_exception_data_type_t> exc_data_value; // Value to compare to exception data after masking, or empty to ignore exc_data value for exception
+ uint8_t flags; // Action flags describing what to do with the exception
+ };
+ static const char *Name(exception_type_t exc_type);
+};
+
+#endif
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.cpp b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.cpp
new file mode 100644
index 0000000..1a0c3c4
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.cpp
@@ -0,0 +1,674 @@
+//===-- MachTask.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachTask.h"
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#if defined (__arm__)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SpringBoardServices/SpringBoardServer.h>
+#include <SpringBoardServices/SBSWatchdogAssertion.h>
+
+#endif
+
+#include "lldb/Host/Host.h"
+#include "lldb/Core/DataExtractor.h"
+
+// Project includes
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// MachTask constructor
+//----------------------------------------------------------------------
+MachTask::MachTask(ProcessMacOSX *process) :
+ m_process (process),
+ m_task (TASK_NULL),
+ m_vm_memory (),
+ m_exception_thread (0),
+ m_exception_port (MACH_PORT_NULL),
+ m_exc_port_info()
+{
+ memset(&m_exc_port_info, 0, sizeof(m_exc_port_info));
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+MachTask::~MachTask()
+{
+ Clear();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Suspend
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::Suspend()
+{
+ Error err;
+ task_t task = GetTaskPort();
+ err = ::task_suspend (task);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_suspend ( target_task = 0x%4.4x )", task);
+ return err.GetError();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Resume
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::Resume()
+{
+ Error err;
+ task_t task = GetTaskPort();
+ err = ::task_resume (task);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_resume ( target_task = 0x%4.4x )", task);
+ return err.GetError();
+}
+
+int32_t
+MachTask::GetSuspendCount () const
+{
+ struct task_basic_info task_info;
+ if (BasicInfo(&task_info) == KERN_SUCCESS)
+ return task_info.suspend_count;
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// MachTask::ExceptionPort
+//----------------------------------------------------------------------
+mach_port_t
+MachTask::ExceptionPort() const
+{
+ return m_exception_port;
+}
+
+//----------------------------------------------------------------------
+// MachTask::ExceptionPortIsValid
+//----------------------------------------------------------------------
+bool
+MachTask::ExceptionPortIsValid() const
+{
+ return MACH_PORT_VALID(m_exception_port);
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Clear
+//----------------------------------------------------------------------
+void
+MachTask::Clear()
+{
+ // Do any cleanup needed for this task
+ m_task = TASK_NULL;
+ m_exception_thread = 0;
+ m_exception_port = MACH_PORT_NULL;
+
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::SaveExceptionPortInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::SaveExceptionPortInfo()
+{
+ return m_exc_port_info.Save(GetTaskPort());
+}
+
+//----------------------------------------------------------------------
+// MachTask::RestoreExceptionPortInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::RestoreExceptionPortInfo()
+{
+ return m_exc_port_info.Restore(GetTaskPort());
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::ReadMemory
+//----------------------------------------------------------------------
+size_t
+MachTask::ReadMemory (lldb::addr_t addr, void *buf, size_t size, Error& error)
+{
+ size_t n = 0;
+ task_t task = GetTaskPort();
+ if (task != TASK_NULL)
+ {
+ n = m_vm_memory.Read(task, addr, buf, size, error);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+ if (log)
+ {
+ log->Printf ("MachTask::ReadMemory ( addr = 0x%16.16llx, size = %zu, buf = %8.8p) => %u bytes read", (uint64_t)addr, size, buf, n);
+ if (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_LONG) || (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_SHORT) && size <= 8))
+ {
+ DataExtractor data((uint8_t*)buf, n, eByteOrderHost, 4);
+ data.PutToLog(log, 0, n, addr, 16, DataExtractor::TypeUInt8);
+ }
+ }
+ }
+ return n;
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::WriteMemory
+//----------------------------------------------------------------------
+size_t
+MachTask::WriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error& error)
+{
+ size_t n = 0;
+ task_t task = GetTaskPort();
+ if (task != TASK_NULL)
+ {
+ n = m_vm_memory.Write(task, addr, buf, size, error);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+ if (log)
+ {
+ log->Printf ("MachTask::WriteMemory ( addr = 0x%16.16llx, size = %zu, buf = %8.8p) => %u bytes written", (uint64_t)addr, size, buf, n);
+ if (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_LONG) || (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_SHORT) && size <= 8))
+ {
+ DataExtractor data((uint8_t*)buf, n, eByteOrderHost, 4);
+ data.PutToLog(log, 0, n, addr, 16, DataExtractor::TypeUInt8);
+ }
+ }
+ }
+ return n;
+}
+
+//----------------------------------------------------------------------
+// MachTask::AllocateMemory
+//----------------------------------------------------------------------
+lldb::addr_t
+MachTask::AllocateMemory (size_t size, uint32_t permissions, Error& error)
+{
+ // FIXME: vm_allocate allocates a page at a time, so we should use
+ // host_page_size to get the host page size and then parcel out the
+ // page we get back until it is filled.
+ // FIXME: Add log messages.
+
+ kern_return_t kret;
+ mach_vm_address_t addr;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+
+ kret = ::mach_vm_allocate (GetTaskPort(), &addr, size, TRUE);
+ if (kret == KERN_SUCCESS)
+ {
+ // Set the protections:
+ vm_prot_t mach_prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ mach_prot |= VM_PROT_READ;
+ if (permissions & lldb::ePermissionsWritable)
+ mach_prot |= VM_PROT_WRITE;
+ if (permissions & lldb::ePermissionsExecutable)
+ mach_prot |= VM_PROT_EXECUTE;
+
+ kret = ::mach_vm_protect (GetTaskPort(), addr, size, 0, mach_prot);
+ if (kret == KERN_SUCCESS)
+ {
+ if (log)
+ log->Printf("Allocated memory at addr = 0x%16.16llx, size = %zu, prot = 0x%x)", (uint64_t) addr, size, mach_prot);
+ m_allocations.insert (std::make_pair(addr, size));
+ return (lldb::addr_t) addr;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Failed to set protections on memory at addr = 0x%16.16llx, size = %zu), prot = 0x%x", (uint64_t) addr, size, mach_prot);
+ kret = ::mach_vm_deallocate (GetTaskPort(), addr, size);
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("Failed to set allocate memory: size = %zu)", size);
+ return LLDB_INVALID_ADDRESS;
+ }
+}
+
+//----------------------------------------------------------------------
+// MachTask::DeallocateMemory
+//----------------------------------------------------------------------
+Error
+MachTask::DeallocateMemory (lldb::addr_t ptr)
+{
+ Error error;
+ // We have to stash away sizes for the allocations...
+ allocation_collection::iterator pos, end = m_allocations.end();
+ for (pos = m_allocations.begin(); pos != end; pos++)
+ {
+ if ((*pos).first == ptr)
+ {
+ m_allocations.erase (pos);
+ error = ::mach_vm_deallocate (GetTaskPort(), (vm_address_t) ptr, (*pos).second);
+ return error;
+ }
+ }
+ error.SetErrorStringWithFormat("no memory allocated at 0x%llx", (uint64_t)ptr);
+ return error;
+}
+
+//----------------------------------------------------------------------
+// MachTask::TaskPortForProcessID
+//----------------------------------------------------------------------
+task_t
+MachTask::GetTaskPortForProcessID (Error &err)
+{
+ err.Clear();
+ if (m_task == TASK_NULL && m_process != NULL)
+ m_task = MachTask::GetTaskPortForProcessID(m_process->GetID(), err);
+ return m_task;
+}
+
+//----------------------------------------------------------------------
+// MachTask::TaskPortForProcessID
+//----------------------------------------------------------------------
+task_t
+MachTask::GetTaskPortForProcessID (lldb::pid_t pid, Error &err)
+{
+ task_t task = TASK_NULL;
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ mach_port_t task_self = mach_task_self ();
+ err = ::task_for_pid ( task_self, pid, &task);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ {
+ err.PutToLog(log, "::task_for_pid ( target_tport = 0x%4.4x, pid = %d, task => 0x%4.4x ) %u/%u %u/%u", task_self, pid, task, getuid(), geteuid(), getgid(), getegid());
+ }
+ }
+ return task;
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::BasicInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::BasicInfo(struct task_basic_info *info) const
+{
+ return BasicInfo (GetTaskPort(), info);
+}
+
+//----------------------------------------------------------------------
+// MachTask::BasicInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::BasicInfo(task_t task, struct task_basic_info *info)
+{
+ if (info == NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ Error err;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
+ err = ::task_info (task, TASK_BASIC_INFO, (task_info_t)info, &count);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_info ( target_task = 0x%4.4x, flavor = TASK_BASIC_INFO, task_info_out => %p, task_info_outCnt => %u )", task, info, count);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE) && err.Success())
+ {
+ float user = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
+ float system = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
+ log->Printf ("task_basic_info = { suspend_count = %i, virtual_size = 0x%8.8x, resident_size = 0x%8.8x, user_time = %f, system_time = %f }",
+ info->suspend_count, info->virtual_size, info->resident_size, user, system);
+ }
+ return err.GetError();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::IsValid
+//
+// Returns true if a task is a valid task port for a current process.
+//----------------------------------------------------------------------
+bool
+MachTask::IsValid () const
+{
+ return MachTask::IsValid(GetTaskPort());
+}
+
+//----------------------------------------------------------------------
+// MachTask::IsValid
+//
+// Returns true if a task is a valid task port for a current process.
+//----------------------------------------------------------------------
+bool
+MachTask::IsValid (task_t task)
+{
+ if (task != TASK_NULL)
+ {
+ struct task_basic_info task_info;
+ return BasicInfo(task, &task_info) == KERN_SUCCESS;
+ }
+ return false;
+}
+
+
+bool
+MachTask::StartExceptionThread(Error &err)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+
+ if (log)
+ log->Printf ("MachTask::%s ( )", __FUNCTION__);
+ task_t task = GetTaskPortForProcessID(err);
+ if (MachTask::IsValid(task))
+ {
+ // Got the mach port for the current process
+ mach_port_t task_self = mach_task_self ();
+
+ // Allocate an exception port that we will use to track our child process
+ err = ::mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE, &m_exception_port);
+ if (log || err.Fail())
+ err.PutToLog(log, "::mach_port_allocate (task_self=0x%4.4x, MACH_PORT_RIGHT_RECEIVE, &m_exception_port => 0x%4.4x)",
+ task_self, m_exception_port);
+ if (err.Fail())
+ return false;
+
+ // Add the ability to send messages on the new exception port
+ err = ::mach_port_insert_right (task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND);
+ if (log || err.Fail())
+ err.PutToLog(log, "::mach_port_insert_right (task_self=0x%4.4x, m_exception_port=0x%4.4x, m_exception_port=0x%4.4x, MACH_MSG_TYPE_MAKE_SEND)",
+ task_self, m_exception_port, m_exception_port);
+ if (err.Fail())
+ return false;
+
+ // Save the original state of the exception ports for our child process
+ err = SaveExceptionPortInfo();
+
+ // Set the ability to get all exceptions on this port
+ err = ::task_set_exception_ports (task, EXC_MASK_ALL, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_set_exception_ports (task, EXC_MASK_ALL, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE)");
+ if (err.Fail())
+ return false;
+
+ // Create the exception thread
+ char thread_name[256];
+ ::snprintf (thread_name, sizeof(thread_name), "<lldb.process.process-macosx.mach-exception-%d>", m_process->GetID());
+ m_exception_thread = Host::ThreadCreate (thread_name, MachTask::ExceptionThread, this, &err);
+
+ return err.Success();
+ }
+ return false;
+}
+
+kern_return_t
+MachTask::ShutDownExceptionThread()
+{
+ Error err;
+
+ if (m_exception_thread == NULL)
+ return KERN_SUCCESS;
+
+ err = RestoreExceptionPortInfo();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+
+ // NULL our our exception port and let our exception thread exit
+ mach_port_t exception_port = m_exception_port;
+ m_exception_port = NULL;
+
+ Host::ThreadCancel (m_exception_thread, &err);
+ if (log || err.Fail())
+ err.PutToLog(log, "Host::ThreadCancel ( thread = %p )", m_exception_thread);
+
+ Host::ThreadJoin (m_exception_thread, NULL, &err);
+ if (log || err.Fail())
+ err.PutToLog(log, "Host::ThreadJoin ( thread = %p, result_ptr = NULL)", m_exception_thread);
+
+ // Deallocate our exception port that we used to track our child process
+ mach_port_t task_self = mach_task_self ();
+ err = ::mach_port_deallocate (task_self, exception_port);
+ if (log || err.Fail())
+ err.PutToLog(log, "::mach_port_deallocate ( task = 0x%4.4x, name = 0x%4.4x )", task_self, exception_port);
+ exception_port = NULL;
+
+ Clear();
+ return err.GetError();
+}
+
+
+void *
+MachTask::ExceptionThread (void *arg)
+{
+ if (arg == NULL)
+ return NULL;
+
+ MachTask *mach_task = (MachTask*) arg;
+ ProcessMacOSX *mach_proc = mach_task->Process();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+ if (log)
+ log->Printf ("MachTask::%s (arg = %p) thread starting...", __FUNCTION__, arg);
+
+ // We keep a count of the number of consecutive exceptions received so
+ // we know to grab all exceptions without a timeout. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main loop in this
+ // thread can stop periodically if needed to service things related to this
+ // process.
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ uint32_t num_exceptions_received = 0;
+ Error err;
+ task_t task = mach_task->GetTaskPort();
+ mach_msg_timeout_t periodic_timeout = 1000;
+
+#if defined (__arm__)
+ mach_msg_timeout_t watchdog_elapsed = 0;
+ mach_msg_timeout_t watchdog_timeout = 60 * 1000;
+ lldb::pid_t pid = mach_proc->GetID();
+ CFReleaser<SBSWatchdogAssertionRef> watchdog;
+
+ if (mach_proc->ProcessUsingSpringBoard())
+ {
+ // Request a renewal for every 60 seconds if we attached using SpringBoard
+ watchdog.reset(::SBSWatchdogAssertionCreateForPID(NULL, pid, 60));
+ if (log)
+ log->Printf ("::SBSWatchdogAssertionCreateForPID (NULL, %4.4x, 60 ) => %p", pid, watchdog.get());
+
+ if (watchdog.get())
+ {
+ ::SBSWatchdogAssertionRenew (watchdog.get());
+
+ CFTimeInterval watchdogRenewalInterval = ::SBSWatchdogAssertionGetRenewalInterval (watchdog.get());
+ if (log)
+ log->Printf ("::SBSWatchdogAssertionGetRenewalInterval ( %p ) => %g seconds", watchdog.get(), watchdogRenewalInterval);
+ if (watchdogRenewalInterval > 0.0)
+ {
+ watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000;
+ if (watchdog_timeout > 3000)
+ watchdog_timeout -= 1000; // Give us a second to renew our timeout
+ else if (watchdog_timeout > 1000)
+ watchdog_timeout -= 250; // Give us a quarter of a second to renew our timeout
+ }
+ }
+ if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout)
+ periodic_timeout = watchdog_timeout;
+ }
+#endif // #if defined (__arm__)
+
+ while (mach_task->ExceptionPortIsValid())
+ {
+ //::pthread_testcancel ();
+
+ MachException::Message exception_message;
+
+
+ if (num_exceptions_received > 0)
+ {
+ // No timeout, just receive as many exceptions as we can since we already have one and we want
+ // to get all currently available exceptions for this task
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0);
+ }
+ else if (periodic_timeout > 0)
+ {
+ // We need to stop periodically in this loop, so try and get a mach message with a valid timeout (ms)
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, periodic_timeout);
+ }
+ else
+ {
+ // We don't need to parse all current exceptions or stop periodically,
+ // just wait for an exception forever.
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0);
+ }
+
+ if (err.GetError() == MACH_RCV_INTERRUPTED)
+ {
+ // If we have no task port we should exit this thread
+ if (!mach_task->ExceptionPortIsValid())
+ {
+ if (log)
+ log->Printf ("thread cancelled...");
+ break;
+ }
+
+ // Make sure our task is still valid
+ if (MachTask::IsValid(task))
+ {
+ // Task is still ok
+ if (log)
+ log->Printf ("interrupted, but task still valid, continuing...");
+ continue;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("task has exited...");
+ mach_proc->SetPrivateState (eStateExited);
+ // Our task has died, exit the thread.
+ break;
+ }
+ }
+ else if (err.GetError() == MACH_RCV_TIMED_OUT)
+ {
+ if (num_exceptions_received > 0)
+ {
+ // We were receiving all current exceptions with a timeout of zero
+ // it is time to go back to our normal looping mode
+ num_exceptions_received = 0;
+
+ // Notify our main thread we have a complete exception message
+ // bundle available.
+ mach_proc->ExceptionMessageBundleComplete();
+
+ // in case we use a timeout value when getting exceptions...
+ // Make sure our task is still valid
+ if (MachTask::IsValid(task))
+ {
+ // Task is still ok
+ if (log)
+ log->Printf ("got a timeout, continuing...");
+ continue;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("task has exited...");
+ mach_proc->SetPrivateState (eStateExited);
+ // Our task has died, exit the thread.
+ break;
+ }
+ continue;
+ }
+
+#if defined (__arm__)
+ if (watchdog.get())
+ {
+ watchdog_elapsed += periodic_timeout;
+ if (watchdog_elapsed >= watchdog_timeout)
+ {
+ LogIf(PD_LOG_TASK, "SBSWatchdogAssertionRenew ( %p )", watchdog.get());
+ ::SBSWatchdogAssertionRenew (watchdog.get());
+ watchdog_elapsed = 0;
+ }
+ }
+#endif
+ }
+ else if (err.GetError() != KERN_SUCCESS)
+ {
+ if (log)
+ log->Printf ("got some other error, do something about it??? nah, continuing for now...");
+ // TODO: notify of error?
+ }
+ else
+ {
+ if (exception_message.CatchExceptionRaise())
+ {
+ ++num_exceptions_received;
+ mach_proc->ExceptionMessageReceived(exception_message);
+ }
+ }
+ }
+
+#if defined (__arm__)
+ if (watchdog.get())
+ {
+ // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel when we
+ // all are up and running on systems that support it. The SBS framework has a #define
+ // that will forward SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel for now
+ // so it should still build either way.
+ LogIf(PD_LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", watchdog.get());
+ ::SBSWatchdogAssertionRelease (watchdog.get());
+ }
+#endif // #if defined (__arm__)
+
+ if (log)
+ log->Printf ("MachTask::%s (arg = %p) thread exiting...", __FUNCTION__, arg);
+ return NULL;
+}
+
+lldb::addr_t
+MachTask::GetDYLDAllImageInfosAddress ()
+{
+#ifdef TASK_DYLD_INFO
+ task_dyld_info_data_t dyld_info;
+ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+ Error err;
+ // The actual task shouldn't matter for the DYLD info, so lets just use ours
+ kern_return_t kret = ::task_info (GetTaskPortForProcessID (err), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
+ if (kret == KERN_SUCCESS)
+ {
+ // We now have the address of the all image infos structure
+ return dyld_info.all_image_info_addr;
+ }
+#endif
+ return LLDB_INVALID_ADDRESS;
+}
+
+
+
+
+
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.h
new file mode 100644
index 0000000..228cb7c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.h
@@ -0,0 +1,138 @@
+//===-- MachTask.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachTask_h__
+#define __MachTask_h__
+
+// C Includes
+// C++ Includes
+#include <map>
+// Other libraries and framework includes
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <sys/socket.h>
+
+// Project includes
+#include "MachException.h"
+#include "MachVMMemory.h"
+
+class ProcessMacOSX;
+
+class MachTask
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ MachTask (ProcessMacOSX *process);
+
+ virtual
+ ~MachTask ();
+
+ void
+ Clear ();
+
+ kern_return_t
+ Suspend ();
+
+ kern_return_t
+ Resume ();
+
+ int32_t
+ GetSuspendCount () const;
+
+ size_t
+ ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error& error);
+
+ size_t
+ WriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error& error);
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions, lldb_private::Error& error);
+
+ lldb_private::Error
+ DeallocateMemory (lldb::addr_t addr);
+
+ mach_port_t
+ ExceptionPort () const;
+
+ bool
+ ExceptionPortIsValid () const;
+
+ kern_return_t
+ SaveExceptionPortInfo ();
+
+ kern_return_t
+ RestoreExceptionPortInfo ();
+
+ kern_return_t
+ ShutDownExceptionThread ();
+
+ bool
+ StartExceptionThread (lldb_private::Error &err);
+
+ lldb::addr_t
+ GetDYLDAllImageInfosAddress ();
+
+ kern_return_t
+ BasicInfo (struct task_basic_info *info) const;
+
+ static kern_return_t
+ BasicInfo (task_t task, struct task_basic_info *info);
+
+ bool
+ IsValid () const;
+
+ static bool
+ IsValid (task_t task);
+
+ static void *
+ ExceptionThread (void *arg);
+
+ task_t
+ GetTaskPort () const
+ {
+ return m_task;
+ }
+
+ task_t
+ GetTaskPortForProcessID (lldb_private::Error &err);
+
+ static task_t
+ GetTaskPortForProcessID (lldb::pid_t pid, lldb_private::Error &err);
+
+ ProcessMacOSX *
+ Process ()
+ {
+ return m_process;
+ }
+
+ const ProcessMacOSX *
+ Process () const
+ {
+ return m_process;
+ }
+
+protected:
+ ProcessMacOSX * m_process; // The mach process that owns this MachTask
+ task_t m_task;
+ MachVMMemory m_vm_memory; // Special mach memory reading class that will take care of watching for page and region boundaries
+ MachException::PortInfo m_exc_port_info; // Saved settings for all exception ports
+ lldb::thread_t m_exception_thread; // Thread ID for the exception thread in case we need it
+ mach_port_t m_exception_port; // Exception port on which we will receive child exceptions
+
+ // Maybe sort this by address and use find?
+ typedef std::map<vm_address_t,size_t> allocation_collection;
+ allocation_collection m_allocations;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (MachTask);
+};
+
+#endif // __MachTask_h__
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext.h
new file mode 100644
index 0000000..3166c28
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext.h
@@ -0,0 +1,48 @@
+//===-- MachThreadContext.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_MachThreadContext_h_
+#define liblldb_MachThreadContext_h_
+
+#include <vector>
+
+#include "MachException.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext
+{
+public:
+ MachThreadContext (ThreadMacOSX &thread) :
+ m_thread (thread)
+ {
+ }
+
+ virtual ~MachThreadContext()
+ {
+ }
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const = 0;
+
+ virtual void InitializeInstance() = 0;
+ virtual void ThreadWillResume () = 0;
+ virtual bool ShouldStop () = 0;
+ virtual void RefreshStateAfterStop() = 0;
+ virtual bool NotifyException (MachException::Data& exc) { return false; }
+ virtual bool StepNotComplete () { return false; }
+ virtual size_t GetStackFrameData(lldb_private::StackFrame *frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs) { return 0; }
+// virtual const uint8_t * SoftwareBreakpointOpcode (size_t byte_size) = 0;
+
+protected:
+ ThreadMacOSX &m_thread;
+
+};
+
+#endif // #ifndef liblldb_MachThreadContext_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.cpp b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.cpp
new file mode 100644
index 0000000..4f6b17c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.cpp
@@ -0,0 +1,1884 @@
+//===-- MachThreadContext_arm.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachThreadContext_arm.h"
+
+#include <sys/sysctl.h>
+
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+#include "ThreadMacOSX.h"
+
+using namespace lldb_private;
+
+//#define DNB_ARCH_MACH_ARM_DEBUG_SW_STEP 1
+
+static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+
+// ARM constants used during decoding
+#define REG_RD 0
+#define LDM_REGLIST 1
+#define PC_REG 15
+#define PC_REGLIST_BIT 0x8000
+
+// ARM conditions
+#define COND_EQ 0x0
+#define COND_NE 0x1
+#define COND_CS 0x2
+#define COND_HS 0x2
+#define COND_CC 0x3
+#define COND_LO 0x3
+#define COND_MI 0x4
+#define COND_PL 0x5
+#define COND_VS 0x6
+#define COND_VC 0x7
+#define COND_HI 0x8
+#define COND_LS 0x9
+#define COND_GE 0xA
+#define COND_LT 0xB
+#define COND_GT 0xC
+#define COND_LE 0xD
+#define COND_AL 0xE
+#define COND_UNCOND 0xF
+
+#define MASK_CPSR_T (1u << 5)
+#define MASK_CPSR_J (1u << 24)
+
+#define MNEMONIC_STRING_SIZE 32
+#define OPERAND_STRING_SIZE 128
+
+using namespace lldb;
+using namespace lldb_private;
+
+MachThreadContext_arm::MachThreadContext_arm(ThreadMacOSX &thread) :
+ MachThreadContext(thread),
+ m_hw_single_chained_step_addr(LLDB_INVALID_ADDRESS),
+ m_bvr0_reg (LLDB_INVALID_REGNUM),
+ m_bcr0_reg (LLDB_INVALID_REGNUM),
+ m_bvr0_save (0),
+ m_bcr0_save (0)
+{
+}
+
+MachThreadContext_arm::~MachThreadContext_arm()
+{
+}
+
+RegisterContext *
+MachThreadContext_arm::CreateRegisterContext (StackFrame *frame) const
+{
+ return new RegisterContextMach_arm(m_thread, frame);
+}
+
+// Instance init function
+void
+MachThreadContext_arm::InitializeInstance()
+{
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx != NULL);
+ const RegisterInfo * reg_info;
+ reg_info = reg_ctx->GetRegisterInfoByName ("bvr0");
+ if (reg_info)
+ m_bvr0_reg = reg_info->reg;
+
+ reg_info = reg_ctx->GetRegisterInfoByName ("bcr0");
+ if (reg_info)
+ m_bcr0_reg = reg_info->reg;
+}
+
+
+
+uint32_t
+MachThreadContext_arm::GetCPUType()
+{
+ return CPU_TYPE_ARM;
+}
+
+void
+MachThreadContext_arm::ThreadWillResume()
+{
+ // Do we need to step this thread? If so, let the mach thread tell us so.
+ if (m_thread.GetState() == eStateStepping)
+ {
+ bool step_handled = false;
+ // This is the primary thread, let the arch do anything it needs
+ if (m_thread.GetRegisterContext()->NumSupportedHardwareBreakpoints() > 0)
+ {
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ bool half_step = m_hw_single_chained_step_addr != LLDB_INVALID_ADDRESS;
+#endif
+ step_handled = EnableHardwareSingleStep(true) == KERN_SUCCESS;
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ if (!half_step)
+ step_handled = false;
+#endif
+ }
+
+#if defined (ENABLE_ARM_SINGLE_STEP)
+ if (!step_handled)
+ {
+ SetSingleStepSoftwareBreakpoints();
+ }
+#endif
+ }
+}
+
+bool
+MachThreadContext_arm::ShouldStop ()
+{
+ return true;
+}
+
+void
+MachThreadContext_arm::RefreshStateAfterStop ()
+{
+ EnableHardwareSingleStep (false) == KERN_SUCCESS;
+}
+
+#if defined (ENABLE_ARM_SINGLE_STEP)
+
+bool
+MachThreadContext_arm::ShouldStop ()
+{
+ return true;
+}
+
+bool
+MachThreadContext_arm::RefreshStateAfterStop ()
+{
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+
+ bool success = true;
+
+ m_state.InvalidateRegisterSet (GPRRegSet);
+ m_state.InvalidateRegisterSet (VFPRegSet);
+ m_state.InvalidateRegisterSet (EXCRegSet);
+
+ // Are we stepping a single instruction?
+ if (ReadGPRRegisters(true) == KERN_SUCCESS)
+ {
+ // We are single stepping, was this the primary thread?
+ if (m_thread.GetState() == eStateStepping)
+ {
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+ // Hardware single step must work if we are going to test software
+ // single step functionality
+ assert(success);
+ if (m_hw_single_chained_step_addr == LLDB_INVALID_ADDRESS && m_sw_single_step_next_pc != LLDB_INVALID_ADDRESS)
+ {
+ uint32_t sw_step_next_pc = m_sw_single_step_next_pc & 0xFFFFFFFEu;
+ bool sw_step_next_pc_is_thumb = (m_sw_single_step_next_pc & 1) != 0;
+ bool actual_next_pc_is_thumb = (m_state.gpr.__cpsr & 0x20) != 0;
+ if (m_state.gpr.r[15] != sw_step_next_pc)
+ {
+ LogError("curr pc = 0x%8.8x - calculated single step target PC was incorrect: 0x%8.8x != 0x%8.8x", m_state.gpr.r[15], sw_step_next_pc, m_state.gpr.r[15]);
+ exit(1);
+ }
+ if (actual_next_pc_is_thumb != sw_step_next_pc_is_thumb)
+ {
+ LogError("curr pc = 0x%8.8x - calculated single step calculated mode mismatch: sw single mode = %s != %s",
+ m_state.gpr.r[15],
+ actual_next_pc_is_thumb ? "Thumb" : "ARM",
+ sw_step_next_pc_is_thumb ? "Thumb" : "ARM");
+ exit(1);
+ }
+ m_sw_single_step_next_pc = LLDB_INVALID_ADDRESS;
+ }
+#else
+#if defined (ENABLE_ARM_SINGLE_STEP)
+ // Are we software single stepping?
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_break_id) || m_sw_single_step_itblock_break_count)
+ {
+ // Remove any software single stepping breakpoints that we have set
+
+ // Do we have a normal software single step breakpoint?
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_break_id))
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: removing software single step breakpoint (breakID=%d)", __FUNCTION__, m_sw_single_step_break_id);
+ success = m_thread.Process()->DisableBreakpoint(m_sw_single_step_break_id, true);
+ m_sw_single_step_break_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ // Do we have any Thumb IT breakpoints?
+ if (m_sw_single_step_itblock_break_count > 0)
+ {
+ // See if we hit one of our Thumb IT breakpoints?
+ DNBBreakpoint *step_bp = m_thread.Process()->Breakpoints().FindByAddress(m_state.gpr.r[15]);
+
+ if (step_bp)
+ {
+ // We did hit our breakpoint, tell the breakpoint it was
+ // hit so that it can run its callback routine and fixup
+ // the PC.
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: IT software single step breakpoint hit (breakID=%u)", __FUNCTION__, step_bp->GetID());
+ step_bp->BreakpointHit(m_thread.Process()->ProcessID(), m_thread.GetID());
+ }
+
+ // Remove all Thumb IT breakpoints
+ for (int i = 0; i < m_sw_single_step_itblock_break_count; i++)
+ {
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: removing IT software single step breakpoint (breakID=%d)", __FUNCTION__, m_sw_single_step_itblock_break_id[i]);
+ success = m_thread.Process()->DisableBreakpoint(m_sw_single_step_itblock_break_id[i], true);
+ m_sw_single_step_itblock_break_id[i] = LLDB_INVALID_BREAK_ID;
+ }
+ }
+ m_sw_single_step_itblock_break_count = 0;
+
+ // Decode instructions up to the current PC to ensure the internal decoder state is valid for the IT block
+ // The decoder has to decode each instruction in the IT block even if it is not executed so that
+ // the fields are correctly updated
+ DecodeITBlockInstructions(m_state.gpr.r[15]);
+ }
+
+ }
+ else
+#endif
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+#endif
+ }
+ else
+ {
+ // The MachThread will automatically restore the suspend count
+ // in ShouldStop (), so we don't need to do anything here if
+ // we weren't the primary thread the last time
+ }
+ }
+ return;
+}
+
+
+
+bool
+MachThreadContext_arm::StepNotComplete ()
+{
+ if (m_hw_single_chained_step_addr != LLDB_INVALID_ADDRESS)
+ {
+ kern_return_t kret = KERN_INVALID_ARGUMENT;
+ kret = ReadGPRRegisters(false);
+ if (kret == KERN_SUCCESS)
+ {
+ if (m_state.gpr.r[15] == m_hw_single_chained_step_addr)
+ {
+ //ProcessMacOSXLog::LogIf(PD_LOG_STEP, "Need to step some more at 0x%8.8x", m_hw_single_chained_step_addr);
+ return true;
+ }
+ }
+ }
+
+ m_hw_single_chained_step_addr = LLDB_INVALID_ADDRESS;
+ return false;
+}
+
+
+void
+MachThreadContext_arm::DecodeITBlockInstructions(lldb::addr_t curr_pc)
+
+{
+ uint16_t opcode16;
+ uint32_t opcode32;
+ lldb::addr_t next_pc_in_itblock;
+ lldb::addr_t pc_in_itblock = m_last_decode_pc;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc);
+
+ // Decode IT block instruction from the instruction following the m_last_decoded_instruction at
+ // PC m_last_decode_pc upto and including the instruction at curr_pc
+ if (m_thread.Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2)
+ {
+ opcode32 = opcode16;
+ pc_in_itblock += 2;
+ // Check for 32 bit thumb opcode and read the upper 16 bits if needed
+ if (((opcode32 & 0xE000) == 0xE000) && opcode32 & 0x1800)
+ {
+ // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for
+ // a 32 bit Thumb opcode
+ // Read bits 31:16 of a 32 bit Thumb opcode
+ if (m_thread.Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2)
+ {
+ pc_in_itblock += 2;
+ // 32 bit thumb opcode
+ opcode32 = (opcode32 << 16) | opcode16;
+ }
+ else
+ {
+ LogError("%s: Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8lx", __FUNCTION__, pc_in_itblock);
+ }
+ }
+ }
+ else
+ {
+ LogError("%s: Error reading 16-bit Thumb instruction at pc=0x%8.8x", __FUNCTION__, pc_in_itblock);
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: pc_in_itblock=0x%8.8x, curr_pc=0x%8.8x", __FUNCTION__, pc_in_itblock, curr_pc);
+
+ next_pc_in_itblock = pc_in_itblock;
+ while (next_pc_in_itblock <= curr_pc)
+ {
+ arm_error_t decodeError;
+
+ m_last_decode_pc = pc_in_itblock;
+ decodeError = DecodeInstructionUsingDisassembler(pc_in_itblock, m_state.gpr.__cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc_in_itblock);
+
+ pc_in_itblock = next_pc_in_itblock;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: next_pc_in_itblock=0x%8.8x", __FUNCTION__, next_pc_in_itblock);
+ }
+}
+
+#endif
+
+// Set the single step bit in the processor status register.
+kern_return_t
+MachThreadContext_arm::EnableHardwareSingleStep (bool enable)
+{
+ Error err;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_STEP);
+
+ if (log) log->Printf("%s( enable = %d )", __FUNCTION__, enable);
+
+ if (m_bvr0_reg == LLDB_INVALID_REGNUM || m_bcr0_reg == LLDB_INVALID_REGNUM)
+ return KERN_INVALID_ARGUMENT;
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ uint32_t bvr = 0;
+ uint32_t bcr = 0;
+
+ const uint32_t i = 0;
+ if (enable)
+ {
+ m_hw_single_chained_step_addr = LLDB_INVALID_ADDRESS;
+
+ // Save our previous state
+ m_bvr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bvr0_reg, 0);
+ m_bcr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bcr0_reg, 0);
+ lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
+ lldb::addr_t cpsr = reg_ctx->GetFlags(0);
+ if (pc == LLDB_INVALID_ADDRESS)
+ return KERN_INVALID_ARGUMENT;
+
+ // Set a breakpoint that will stop when the PC doesn't match the current one!
+ bvr = pc & 0xFFFFFFFCu; // Set the current PC as the breakpoint address
+ bcr = BCR_M_IMVA_MISMATCH | // Stop on address mismatch
+ S_USER | // Stop only in user mode
+ BCR_ENABLE; // Enable this breakpoint
+ if (cpsr & 0x20)
+ {
+ // Thumb breakpoint
+ if (pc & 2)
+ bcr |= BAS_IMVA_2_3;
+ else
+ bcr |= BAS_IMVA_0_1;
+
+ uint16_t opcode;
+ Error error;
+ if (sizeof(opcode) == m_thread.GetProcess().ReadMemory(pc, &opcode, sizeof(opcode), error))
+ {
+ if (((opcode & 0xE000) == 0xE000) && opcode & 0x1800)
+ {
+ // 32 bit thumb opcode...
+ if (pc & 2)
+ {
+ // We can't take care of a 32 bit thumb instruction single step
+ // with just IVA mismatching. We will need to chain an extra
+ // hardware single step in order to complete this single step...
+ m_hw_single_chained_step_addr = pc + 2;
+ }
+ else
+ {
+ // Extend the number of bits to ignore for the mismatch
+ bcr |= BAS_IMVA_ALL;
+ }
+ }
+ }
+ }
+ else
+ {
+ // ARM breakpoint
+ bcr |= BAS_IMVA_ALL; // Stop when any address bits change
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: BVR%u=0x%8.8x BCR%u=0x%8.8x", __FUNCTION__, i, bvr, i, bcr);
+
+ m_bvr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bvr0_reg, 0);
+ m_bcr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bcr0_reg, 0);
+
+// for (uint32_t j=i+1; j<16; ++j)
+// {
+// // Disable all others
+// m_state.dbg.bvr[j] = 0;
+// m_state.dbg.bcr[j] = 0;
+// }
+ }
+ else
+ {
+ // Just restore the state we had before we did single stepping
+ bvr = m_bvr0_save;
+ bcr = m_bcr0_save;
+ }
+
+ if (reg_ctx->WriteRegisterFromUnsigned(m_bvr0_reg, bvr) &&
+ reg_ctx->WriteRegisterFromUnsigned(m_bcr0_reg, bcr))
+ return KERN_SUCCESS;
+
+ return KERN_INVALID_ARGUMENT;
+}
+
+#if defined (ENABLE_ARM_SINGLE_STEP)
+
+// return 1 if bit "BIT" is set in "value"
+static inline uint32_t bit(uint32_t value, uint32_t bit)
+{
+ return (value >> bit) & 1u;
+}
+
+// return the bitfield "value[msbit:lsbit]".
+static inline uint32_t bits(uint32_t value, uint32_t msbit, uint32_t lsbit)
+{
+ assert(msbit >= lsbit);
+ uint32_t shift_left = sizeof(value) * 8 - 1 - msbit;
+ value <<= shift_left; // shift anything above the msbit off of the unsigned edge
+ value >>= shift_left + lsbit; // shift it back again down to the lsbit (including undoing any shift from above)
+ return value; // return our result
+}
+
+bool
+MachThreadContext_arm::ConditionPassed(uint8_t condition, uint32_t cpsr)
+{
+ uint32_t cpsr_n = bit(cpsr, 31); // Negative condition code flag
+ uint32_t cpsr_z = bit(cpsr, 30); // Zero condition code flag
+ uint32_t cpsr_c = bit(cpsr, 29); // Carry condition code flag
+ uint32_t cpsr_v = bit(cpsr, 28); // Overflow condition code flag
+
+ switch (condition) {
+ case COND_EQ: // (0x0)
+ if (cpsr_z == 1) return true;
+ break;
+ case COND_NE: // (0x1)
+ if (cpsr_z == 0) return true;
+ break;
+ case COND_CS: // (0x2)
+ if (cpsr_c == 1) return true;
+ break;
+ case COND_CC: // (0x3)
+ if (cpsr_c == 0) return true;
+ break;
+ case COND_MI: // (0x4)
+ if (cpsr_n == 1) return true;
+ break;
+ case COND_PL: // (0x5)
+ if (cpsr_n == 0) return true;
+ break;
+ case COND_VS: // (0x6)
+ if (cpsr_v == 1) return true;
+ break;
+ case COND_VC: // (0x7)
+ if (cpsr_v == 0) return true;
+ break;
+ case COND_HI: // (0x8)
+ if ((cpsr_c == 1) && (cpsr_z == 0)) return true;
+ break;
+ case COND_LS: // (0x9)
+ if ((cpsr_c == 0) || (cpsr_z == 1)) return true;
+ break;
+ case COND_GE: // (0xA)
+ if (cpsr_n == cpsr_v) return true;
+ break;
+ case COND_LT: // (0xB)
+ if (cpsr_n != cpsr_v) return true;
+ break;
+ case COND_GT: // (0xC)
+ if ((cpsr_z == 0) && (cpsr_n == cpsr_v)) return true;
+ break;
+ case COND_LE: // (0xD)
+ if ((cpsr_z == 1) || (cpsr_n != cpsr_v)) return true;
+ break;
+ default:
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool
+MachThreadContext_arm::ComputeNextPC(lldb::addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, lldb::addr_t *targetPC)
+{
+ lldb::addr_t myTargetPC, addressWherePCLives;
+ lldb::pid_t mypid;
+
+ uint32_t cpsr_c = bit(m_state.gpr.cpsr, 29); // Carry condition code flag
+
+ uint32_t firstOperand=0, secondOperand=0, shiftAmount=0, secondOperandAfterShift=0, immediateValue=0;
+ uint32_t halfwords=0, baseAddress=0, immediateOffset=0, addressOffsetFromRegister=0, addressOffsetFromRegisterAfterShift;
+ uint32_t baseAddressIndex=LLDB_INVALID_INDEX32;
+ uint32_t firstOperandIndex=LLDB_INVALID_INDEX32;
+ uint32_t secondOperandIndex=LLDB_INVALID_INDEX32;
+ uint32_t addressOffsetFromRegisterIndex=LLDB_INVALID_INDEX32;
+ uint32_t shiftRegisterIndex=LLDB_INVALID_INDEX32;
+ uint16_t registerList16, registerList16NoPC;
+ uint8_t registerList8;
+ uint32_t numRegistersToLoad=0;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: instruction->code=%d", __FUNCTION__, decodedInstruction.instruction->code);
+
+ // Get the following in this switch statement:
+ // - firstOperand, secondOperand, immediateValue, shiftAmount: For arithmetic, logical and move instructions
+ // - baseAddress, immediateOffset, shiftAmount: For LDR
+ // - numRegistersToLoad: For LDM and POP instructions
+ switch (decodedInstruction.instruction->code)
+ {
+ // Arithmetic operations that can change the PC
+ case ARM_INST_ADC:
+ case ARM_INST_ADCS:
+ case ARM_INST_ADD:
+ case ARM_INST_ADDS:
+ case ARM_INST_AND:
+ case ARM_INST_ANDS:
+ case ARM_INST_ASR:
+ case ARM_INST_ASRS:
+ case ARM_INST_BIC:
+ case ARM_INST_BICS:
+ case ARM_INST_EOR:
+ case ARM_INST_EORS:
+ case ARM_INST_ORR:
+ case ARM_INST_ORRS:
+ case ARM_INST_RSB:
+ case ARM_INST_RSBS:
+ case ARM_INST_RSC:
+ case ARM_INST_RSCS:
+ case ARM_INST_SBC:
+ case ARM_INST_SBCS:
+ case ARM_INST_SUB:
+ case ARM_INST_SUBS:
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_DATA_IMM:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get immediateValue (at index=2)
+ immediateValue = decodedInstruction.op[2].value;
+
+ break;
+
+ case ARM_ADDR_DATA_REG:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ case ARM_ADDR_DATA_SCALED_IMM:
+ if (decodedInstruction.numOperands != 4)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount as immediate value (at index=3)
+ shiftAmount = decodedInstruction.op[3].value;
+
+ break;
+
+
+ case ARM_ADDR_DATA_SCALED_REG:
+ if (decodedInstruction.numOperands != 4)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount from register (at index=3)
+ shiftRegisterIndex = decodedInstruction.op[3].value; // second operand register index
+ shiftAmount = m_state.gpr.r[shiftRegisterIndex];
+
+ break;
+
+ case THUMB_ADDR_HR_HR:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=0)
+ firstOperandIndex = decodedInstruction.op[0].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ // Logical shifts and move operations that can change the PC
+ case ARM_INST_LSL:
+ case ARM_INST_LSLS:
+ case ARM_INST_LSR:
+ case ARM_INST_LSRS:
+ case ARM_INST_MOV:
+ case ARM_INST_MOVS:
+ case ARM_INST_MVN:
+ case ARM_INST_MVNS:
+ case ARM_INST_ROR:
+ case ARM_INST_RORS:
+ case ARM_INST_RRX:
+ case ARM_INST_RRXS:
+ // In these cases, the firstOperand is always 0, as if it does not exist
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_DATA_IMM:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get immediateValue (at index=1)
+ immediateValue = decodedInstruction.op[1].value;
+
+ break;
+
+ case ARM_ADDR_DATA_REG:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ case ARM_ADDR_DATA_SCALED_IMM:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount as immediate value (at index=2)
+ shiftAmount = decodedInstruction.op[2].value;
+
+ break;
+
+
+ case ARM_ADDR_DATA_SCALED_REG:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount from register (at index=2)
+ shiftRegisterIndex = decodedInstruction.op[2].value; // second operand register index
+ shiftAmount = m_state.gpr.r[shiftRegisterIndex];
+
+ break;
+
+ case THUMB_ADDR_HR_HR:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ // Simple branches, used to hop around within a routine
+ case ARM_INST_B:
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ break;
+
+ // Branch-and-link, used to call ARM subroutines
+ case ARM_INST_BL:
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ break;
+
+ // Branch-and-link with exchange, used to call opposite-mode subroutines
+ case ARM_INST_BLX:
+ if ((decodedInstruction.addressMode == ARM_ADDR_BRANCH_IMM) ||
+ (decodedInstruction.addressMode == THUMB_ADDR_UNCOND))
+ {
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+ else // addressMode == ARM_ADDR_BRANCH_REG
+ {
+ // Unknown target unless we're branching to the PC itself,
+ // although this may not work properly with BLX
+ if (decodedInstruction.op[REG_RD].value == PC_REG)
+ {
+ // this should (almost) never happen
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 1)
+ {
+ LogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address in register (at index=0)
+ *targetPC = m_state.gpr.r[decodedInstruction.op[0].value];
+ return true;
+ }
+ break;
+
+ // Branch with exchange, used to hop to opposite-mode code
+ // Branch to Jazelle code, used to execute Java; included here since it
+ // acts just like BX unless the Jazelle unit is active and JPC is
+ // already loaded into it.
+ case ARM_INST_BX:
+ case ARM_INST_BXJ:
+ // Unknown target unless we're branching to the PC itself,
+ // although this can never switch to Thumb mode and is
+ // therefore pretty much useless
+ if (decodedInstruction.op[REG_RD].value == PC_REG)
+ {
+ // this should (almost) never happen
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 1)
+ {
+ LogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address in register (at index=0)
+ *targetPC = m_state.gpr.r[decodedInstruction.op[0].value];
+ return true;
+ break;
+
+ // Compare and branch on zero/non-zero (Thumb-16 only)
+ // Unusual condition check built into the instruction
+ case ARM_INST_CBZ:
+ case ARM_INST_CBNZ:
+ // Branch address is known at compile time
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address as an immediate value (at index=1)
+ *targetPC = decodedInstruction.op[1].value;
+ return true;
+ break;
+
+ // Load register can be used to load PC, usually with a function pointer
+ case ARM_INST_LDR:
+ if (decodedInstruction.op[REG_RD].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_LSWUB_IMM:
+ case ARM_ADDR_LSWUB_IMM_PRE:
+ case ARM_ADDR_LSWUB_IMM_POST:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset (at index=2)
+ immediateOffset = decodedInstruction.op[2].value;
+ break;
+
+ case ARM_ADDR_LSWUB_REG:
+ case ARM_ADDR_LSWUB_REG_PRE:
+ case ARM_ADDR_LSWUB_REG_POST:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=2)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[2].value;
+ addressOffsetFromRegister = m_state.gpr.r[addressOffsetFromRegisterIndex];
+
+ break;
+
+ case ARM_ADDR_LSWUB_SCALED:
+ case ARM_ADDR_LSWUB_SCALED_PRE:
+ case ARM_ADDR_LSWUB_SCALED_POST:
+ if (decodedInstruction.numOperands != 4)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=2)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[2].value;
+ addressOffsetFromRegister = m_state.gpr.r[addressOffsetFromRegisterIndex];
+
+ // Get shiftAmount (at index=3)
+ shiftAmount = decodedInstruction.op[3].value;
+
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ // 32b load multiple operations can load the PC along with everything else,
+ // usually to return from a function call
+ case ARM_INST_LDMDA:
+ case ARM_INST_LDMDB:
+ case ARM_INST_LDMIA:
+ case ARM_INST_LDMIB:
+ if (decodedInstruction.op[LDM_REGLIST].value & PC_REGLIST_BIT)
+ {
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=0)
+ baseAddressIndex = decodedInstruction.op[0].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get registerList from register (at index=1)
+ registerList16 = (uint16_t)decodedInstruction.op[1].value;
+
+ // Count number of registers to load in the multiple register list excluding the PC
+ registerList16NoPC = registerList16&0x3FFF; // exclude the PC
+ numRegistersToLoad=0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (registerList16NoPC & 0x1) numRegistersToLoad++;
+ registerList16NoPC = registerList16NoPC >> 1;
+ }
+ }
+ else
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+ break;
+
+ // Normal 16-bit LD multiple can't touch R15, but POP can
+ case ARM_INST_POP: // Can also get the PC & updates SP
+ // Get baseAddress from SP (at index=0)
+ baseAddress = m_state.gpr.__sp;
+
+ if (decodedInstruction.thumb16b)
+ {
+ // Get registerList from register (at index=0)
+ registerList8 = (uint8_t)decodedInstruction.op[0].value;
+
+ // Count number of registers to load in the multiple register list
+ numRegistersToLoad=0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (registerList8 & 0x1) numRegistersToLoad++;
+ registerList8 = registerList8 >> 1;
+ }
+ }
+ else
+ {
+ // Get registerList from register (at index=0)
+ registerList16 = (uint16_t)decodedInstruction.op[0].value;
+
+ // Count number of registers to load in the multiple register list excluding the PC
+ registerList16NoPC = registerList16&0x3FFF; // exclude the PC
+ numRegistersToLoad=0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (registerList16NoPC & 0x1) numRegistersToLoad++;
+ registerList16NoPC = registerList16NoPC >> 1;
+ }
+ }
+ break;
+
+ // 16b TBB and TBH instructions load a jump address from a table
+ case ARM_INST_TBB:
+ case ARM_INST_TBH:
+ // Get baseAddress from register (at index=0)
+ baseAddressIndex = decodedInstruction.op[0].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=1)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[1].value;
+ addressOffsetFromRegister = m_state.gpr.r[addressOffsetFromRegisterIndex];
+ break;
+
+ // ThumbEE branch-to-handler instructions: Jump to handlers at some offset
+ // from a special base pointer register (which is unknown at disassembly time)
+ case ARM_INST_HB:
+ case ARM_INST_HBP:
+// TODO: ARM_INST_HB, ARM_INST_HBP
+ break;
+
+ case ARM_INST_HBL:
+ case ARM_INST_HBLP:
+// TODO: ARM_INST_HBL, ARM_INST_HBLP
+ break;
+
+ // Breakpoint and software interrupt jump to interrupt handler (always ARM)
+ case ARM_INST_BKPT:
+ case ARM_INST_SMC:
+ case ARM_INST_SVC:
+
+ // Return from exception, obviously modifies PC [interrupt only!]
+ case ARM_INST_RFEDA:
+ case ARM_INST_RFEDB:
+ case ARM_INST_RFEIA:
+ case ARM_INST_RFEIB:
+
+ // Other instructions either can't change R15 or are "undefined" if you do,
+ // so no sane compiler should ever generate them & we don't care here.
+ // Also, R15 can only legally be used in a read-only manner for the
+ // various ARM addressing mode (to get PC-relative addressing of constants),
+ // but can NOT be used with any of the update modes.
+ default:
+ LogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code);
+ return false;
+ break;
+ }
+
+ // Adjust PC if PC is one of the input operands
+ if (baseAddressIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ baseAddress += 4;
+ else
+ baseAddress += 8;
+ }
+
+ if (firstOperandIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ firstOperand += 4;
+ else
+ firstOperand += 8;
+ }
+
+ if (secondOperandIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ secondOperand += 4;
+ else
+ secondOperand += 8;
+ }
+
+ if (addressOffsetFromRegisterIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ addressOffsetFromRegister += 4;
+ else
+ addressOffsetFromRegister += 8;
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE,
+ "%s: firstOperand=%8.8x, secondOperand=%8.8x, immediateValue = %d, shiftAmount = %d, baseAddress = %8.8x, addressOffsetFromRegister = %8.8x, immediateOffset = %d, numRegistersToLoad = %d",
+ __FUNCTION__,
+ firstOperand,
+ secondOperand,
+ immediateValue,
+ shiftAmount,
+ baseAddress,
+ addressOffsetFromRegister,
+ immediateOffset,
+ numRegistersToLoad);
+
+
+ // Calculate following values after applying shiftAmount:
+ // - immediateOffsetAfterShift, secondOperandAfterShift
+
+ switch (decodedInstruction.scaleMode)
+ {
+ case ARM_SCALE_NONE:
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister;
+ secondOperandAfterShift = secondOperand;
+ break;
+
+ case ARM_SCALE_LSL: // Logical shift left
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister << shiftAmount;
+ secondOperandAfterShift = secondOperand << shiftAmount;
+ break;
+
+ case ARM_SCALE_LSR: // Logical shift right
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister >> shiftAmount;
+ secondOperandAfterShift = secondOperand >> shiftAmount;
+ break;
+
+ case ARM_SCALE_ASR: // Arithmetic shift right
+ asm("mov %0, %1, asr %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount));
+ asm("mov %0, %1, asr %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount));
+ break;
+
+ case ARM_SCALE_ROR: // Rotate right
+ asm("mov %0, %1, ror %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount));
+ asm("mov %0, %1, ror %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount));
+ break;
+
+ case ARM_SCALE_RRX: // Rotate right, pulling in carry (1-bit shift only)
+ asm("mov %0, %1, rrx" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister));
+ asm("mov %0, %1, rrx" : "=r" (secondOperandAfterShift) : "r" (secondOperand));
+ break;
+ }
+
+ // Emulate instruction to calculate targetPC
+ // All branches are already handled in the first switch statement. A branch should not reach this switch
+ switch (decodedInstruction.instruction->code)
+ {
+ // Arithmetic operations that can change the PC
+ case ARM_INST_ADC:
+ case ARM_INST_ADCS:
+ // Add with Carry
+ *targetPC = firstOperand + (secondOperandAfterShift + immediateValue) + cpsr_c;
+ break;
+
+ case ARM_INST_ADD:
+ case ARM_INST_ADDS:
+ *targetPC = firstOperand + (secondOperandAfterShift + immediateValue);
+ break;
+
+ case ARM_INST_AND:
+ case ARM_INST_ANDS:
+ *targetPC = firstOperand & (secondOperandAfterShift + immediateValue);
+ break;
+
+ case ARM_INST_ASR:
+ case ARM_INST_ASRS:
+ asm("mov %0, %1, asr %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_BIC:
+ case ARM_INST_BICS:
+ asm("bic %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_EOR:
+ case ARM_INST_EORS:
+ asm("eor %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_ORR:
+ case ARM_INST_ORRS:
+ asm("orr %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_RSB:
+ case ARM_INST_RSBS:
+ asm("rsb %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_RSC:
+ case ARM_INST_RSCS:
+ myTargetPC = secondOperandAfterShift - (firstOperand + !cpsr_c);
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_SBC:
+ case ARM_INST_SBCS:
+ asm("sbc %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue + !cpsr_c));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_SUB:
+ case ARM_INST_SUBS:
+ asm("sub %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ // Logical shifts and move operations that can change the PC
+ case ARM_INST_LSL:
+ case ARM_INST_LSLS:
+ case ARM_INST_LSR:
+ case ARM_INST_LSRS:
+ case ARM_INST_MOV:
+ case ARM_INST_MOVS:
+ case ARM_INST_ROR:
+ case ARM_INST_RORS:
+ case ARM_INST_RRX:
+ case ARM_INST_RRXS:
+ myTargetPC = secondOperandAfterShift + immediateValue;
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_MVN:
+ case ARM_INST_MVNS:
+ myTargetPC = !(secondOperandAfterShift + immediateValue);
+ *targetPC = myTargetPC;
+ break;
+
+ // Load register can be used to load PC, usually with a function pointer
+ case ARM_INST_LDR:
+ switch (decodedInstruction.addressMode) {
+ case ARM_ADDR_LSWUB_IMM_POST:
+ case ARM_ADDR_LSWUB_REG_POST:
+ case ARM_ADDR_LSWUB_SCALED_POST:
+ addressWherePCLives = baseAddress;
+ break;
+
+ case ARM_ADDR_LSWUB_IMM:
+ case ARM_ADDR_LSWUB_REG:
+ case ARM_ADDR_LSWUB_SCALED:
+ case ARM_ADDR_LSWUB_IMM_PRE:
+ case ARM_ADDR_LSWUB_REG_PRE:
+ case ARM_ADDR_LSWUB_SCALED_PRE:
+ addressWherePCLives = baseAddress + (addressOffsetFromRegisterAfterShift + immediateOffset);
+ break;
+
+ default:
+ break;
+ }
+
+ mypid = m_thread.ProcessID();
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ // 32b load multiple operations can load the PC along with everything else,
+ // usually to return from a function call
+ case ARM_INST_LDMDA:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMDB:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress - 4;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMIB:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress + numRegistersToLoad*4 + 4;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMIA: // same as pop
+ // Normal 16-bit LD multiple can't touch R15, but POP can
+ case ARM_INST_POP: // Can also get the PC & updates SP
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress + numRegistersToLoad*4;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ // 16b TBB and TBH instructions load a jump address from a table
+ case ARM_INST_TBB:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress + addressOffsetFromRegisterAfterShift;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, 1, &halfwords) != 1)
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the TBB instruction!", addressWherePCLives);
+ return false;
+ }
+ // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords
+ *targetPC = (currentPC + 4) + 2*halfwords;
+ break;
+
+ case ARM_INST_TBH:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = ((baseAddress + (addressOffsetFromRegisterAfterShift << 1)) & ~0x1);
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, 2, &halfwords) != 2)
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the TBH instruction!", addressWherePCLives);
+ return false;
+ }
+ // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords
+ *targetPC = (currentPC + 4) + 2*halfwords;
+ break;
+
+ // ThumbEE branch-to-handler instructions: Jump to handlers at some offset
+ // from a special base pointer register (which is unknown at disassembly time)
+ case ARM_INST_HB:
+ case ARM_INST_HBP:
+ // TODO: ARM_INST_HB, ARM_INST_HBP
+ break;
+
+ case ARM_INST_HBL:
+ case ARM_INST_HBLP:
+ // TODO: ARM_INST_HBL, ARM_INST_HBLP
+ break;
+
+ // Breakpoint and software interrupt jump to interrupt handler (always ARM)
+ case ARM_INST_BKPT:
+ case ARM_INST_SMC:
+ case ARM_INST_SVC:
+ // TODO: ARM_INST_BKPT, ARM_INST_SMC, ARM_INST_SVC
+ break;
+
+ // Return from exception, obviously modifies PC [interrupt only!]
+ case ARM_INST_RFEDA:
+ case ARM_INST_RFEDB:
+ case ARM_INST_RFEIA:
+ case ARM_INST_RFEIB:
+ // TODO: ARM_INST_RFEDA, ARM_INST_RFEDB, ARM_INST_RFEIA, ARM_INST_RFEIB
+ break;
+
+ // Other instructions either can't change R15 or are "undefined" if you do,
+ // so no sane compiler should ever generate them & we don't care here.
+ // Also, R15 can only legally be used in a read-only manner for the
+ // various ARM addressing mode (to get PC-relative addressing of constants),
+ // but can NOT be used with any of the update modes.
+ default:
+ LogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code);
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+void
+MachThreadContext_arm::EvaluateNextInstructionForSoftwareBreakpointSetup(lldb::addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, lldb::addr_t *nextPC, bool *nextPCIsThumb)
+{
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "MachThreadContext_arm::EvaluateNextInstructionForSoftwareBreakpointSetup() called");
+
+ lldb::addr_t targetPC = LLDB_INVALID_ADDRESS;
+ uint32_t registerValue;
+ arm_error_t decodeError;
+ lldb::addr_t currentPCInITBlock, nextPCInITBlock;
+ int i;
+ bool last_decoded_instruction_executes = true;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: default nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM");
+
+ // Update *nextPC and *nextPCIsThumb for special cases
+ if (m_last_decode_thumb.itBlockRemaining) // we are in an IT block
+ {
+ // Set the nextPC to the PC of the instruction which will execute in the IT block
+ // If none of the instruction execute in the IT block based on the condition flags,
+ // then point to the instruction immediately following the IT block
+ const int itBlockRemaining = m_last_decode_thumb.itBlockRemaining;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: itBlockRemaining=%8.8x", __FUNCTION__, itBlockRemaining);
+
+ // Determine the PC at which the next instruction resides
+ if (m_last_decode_arm.thumb16b)
+ currentPCInITBlock = currentPC + 2;
+ else
+ currentPCInITBlock = currentPC + 4;
+
+ for (i = 0; i < itBlockRemaining; i++)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: currentPCInITBlock=%8.8x", __FUNCTION__, currentPCInITBlock);
+ decodeError = DecodeInstructionUsingDisassembler(currentPCInITBlock, cpsr, &m_last_decode_arm, &m_last_decode_thumb, &nextPCInITBlock);
+
+ if (decodeError != ARM_SUCCESS)
+ LogError("unable to disassemble instruction at 0x%8.8lx", currentPCInITBlock);
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: condition=%d", __FUNCTION__, m_last_decode_arm.condition);
+ if (ConditionPassed(m_last_decode_arm.condition, cpsr))
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition codes matched for instruction %d", __FUNCTION__, i);
+ break; // break from the for loop
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition codes DID NOT matched for instruction %d", __FUNCTION__, i);
+ }
+
+ // update currentPC and nextPCInITBlock
+ currentPCInITBlock = nextPCInITBlock;
+ }
+
+ if (i == itBlockRemaining) // We came out of the IT block without executing any instructions
+ last_decoded_instruction_executes = false;
+
+ *nextPC = currentPCInITBlock;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: After IT block step-through: *nextPC=%8.8x", __FUNCTION__, *nextPC);
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE,
+ "%s: cpsr = %8.8x, thumb16b = %d, thumb = %d, branch = %d, conditional = %d, knownTarget = %d, links = %d, canSwitchMode = %d, doesSwitchMode = %d",
+ __FUNCTION__,
+ cpsr,
+ m_last_decode_arm.thumb16b,
+ m_last_decode_arm.thumb,
+ m_last_decode_arm.branch,
+ m_last_decode_arm.conditional,
+ m_last_decode_arm.knownTarget,
+ m_last_decode_arm.links,
+ m_last_decode_arm.canSwitchMode,
+ m_last_decode_arm.doesSwitchMode);
+
+
+ if (last_decoded_instruction_executes && // Was this a conditional instruction that did execute?
+ m_last_decode_arm.branch && // Can this instruction change the PC?
+ (m_last_decode_arm.instruction->code != ARM_INST_SVC)) // If this instruction is not an SVC instruction
+ {
+ // Set targetPC. Compute if needed.
+ if (m_last_decode_arm.knownTarget)
+ {
+ // Fixed, known PC-relative
+ targetPC = m_last_decode_arm.targetPC;
+ }
+ else
+ {
+ // if targetPC is not known at compile time (PC-relative target), compute targetPC
+ if (!ComputeNextPC(currentPC, m_last_decode_arm, currentPCIsThumb, &targetPC))
+ {
+ LogError("%s: Unable to compute targetPC for instruction at 0x%8.8lx", __FUNCTION__, currentPC);
+ targetPC = LLDB_INVALID_ADDRESS;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: targetPC=0x%8.8x, cpsr=0x%8.8x, condition=0x%hhx", __FUNCTION__, targetPC, cpsr, m_last_decode_arm.condition);
+
+ // Refine nextPC computation
+ if ((m_last_decode_arm.instruction->code == ARM_INST_CBZ) ||
+ (m_last_decode_arm.instruction->code == ARM_INST_CBNZ))
+ {
+ // Compare and branch on zero/non-zero (Thumb-16 only)
+ // Unusual condition check built into the instruction
+ registerValue = m_state.gpr.r[m_last_decode_arm.op[REG_RD].value];
+
+ if (m_last_decode_arm.instruction->code == ARM_INST_CBZ)
+ {
+ if (registerValue == 0)
+ *nextPC = targetPC;
+ }
+ else
+ {
+ if (registerValue != 0)
+ *nextPC = targetPC;
+ }
+ }
+ else if (m_last_decode_arm.conditional) // Is the change conditional on flag results?
+ {
+ if (ConditionPassed(m_last_decode_arm.condition, cpsr)) // conditions match
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition matched!", __FUNCTION__);
+ *nextPC = targetPC;
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition did not match!", __FUNCTION__);
+ }
+ }
+ else
+ {
+ *nextPC = targetPC;
+ }
+
+ // Refine nextPCIsThumb computation
+ if (m_last_decode_arm.doesSwitchMode)
+ {
+ *nextPCIsThumb = !currentPCIsThumb;
+ }
+ else if (m_last_decode_arm.canSwitchMode)
+ {
+ // Legal to switch ARM <--> Thumb mode with this branch
+ // dependent on bit[0] of targetPC
+ *nextPCIsThumb = (*nextPC & 1u) != 0;
+ }
+ else
+ {
+ *nextPCIsThumb = currentPCIsThumb;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: calculated nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM");
+}
+
+
+arm_error_t
+MachThreadContext_arm::DecodeInstructionUsingDisassembler(lldb::addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, lldb::addr_t *next_pc)
+{
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: pc=0x%8.8x, cpsr=0x%8.8x", __FUNCTION__, curr_pc, curr_cpsr);
+
+ const uint32_t isetstate_mask = MASK_CPSR_T | MASK_CPSR_J;
+ const uint32_t curr_isetstate = curr_cpsr & isetstate_mask;
+ uint32_t opcode32;
+ lldb::addr_t nextPC = curr_pc;
+ arm_error_t decodeReturnCode = ARM_SUCCESS;
+
+ m_last_decode_pc = curr_pc;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc);
+
+ switch (curr_isetstate) {
+ case 0x0: // ARM Instruction
+ // Read the ARM opcode
+ if (m_thread.Process()->Task().ReadMemory(curr_pc, 4, &opcode32) != 4)
+ {
+ LogError("unable to read opcode bits 31:0 for an ARM opcode at 0x%8.8lx", curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ }
+ else
+ {
+ nextPC += 4;
+ decodeReturnCode = ArmDisassembler((uint64_t)curr_pc, opcode32, false, decodedInstruction, NULL, 0, NULL, 0);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ LogError("Unable to decode ARM instruction 0x%8.8x at 0x%8.8lx", opcode32, curr_pc);
+ }
+ break;
+
+ case 0x20: // Thumb Instruction
+ uint16_t opcode16;
+ // Read the a 16 bit Thumb opcode
+ if (m_thread.Process()->Task().ReadMemory(curr_pc, 2, &opcode16) != 2)
+ {
+ LogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8lx", curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ }
+ else
+ {
+ nextPC += 2;
+ opcode32 = opcode16;
+
+ decodeReturnCode = ThumbDisassembler((uint64_t)curr_pc, opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0);
+
+ switch (decodeReturnCode) {
+ case ARM_SKIP:
+ // 32 bit thumb opcode
+ nextPC += 2;
+ if (m_thread.Process()->Task().ReadMemory(curr_pc+2, 2, &opcode16) != 2)
+ {
+ LogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8lx", curr_pc+2);
+ }
+ else
+ {
+ opcode32 = (opcode32 << 16) | opcode16;
+
+ decodeReturnCode = ThumbDisassembler((uint64_t)(curr_pc+2), opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ LogError("Unable to decode 2nd half of Thumb instruction 0x%8.4hx at 0x%8.8lx", opcode16, curr_pc+2);
+ break;
+ }
+ break;
+
+ case ARM_SUCCESS:
+ // 16 bit thumb opcode; at this point we are done decoding the opcode
+ break;
+
+ default:
+ LogError("Unable to decode Thumb instruction 0x%8.4hx at 0x%8.8lx", opcode16, curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (next_pc)
+ *next_pc = nextPC;
+
+ return decodeReturnCode;
+}
+
+bool
+MachThreadContext_arm::BreakpointHit(lldb::pid_t pid, lldb::tid_t tid, lldb::user_id_t breakID, void *baton)
+{
+ lldb::addr_t bkpt_pc = (lldb::addr_t)baton;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s(pid = %i, tid = %4.4x, breakID = %u, baton = %p): Setting PC to 0x%8.8x", __FUNCTION__, pid, tid, breakID, baton, bkpt_pc);
+ return PDThreadSetRegisterValueByID(pid, tid, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, bkpt_pc);
+}
+
+// Set the single step bit in the processor status register.
+kern_return_t
+MachThreadContext_arm::SetSingleStepSoftwareBreakpoints()
+{
+ Error err;
+ err = ReadGPRRegisters(false);
+
+ if (err.Fail())
+ {
+ err.Log("%s: failed to read the GPR registers", __FUNCTION__);
+ return err.GetError();
+ }
+
+ lldb::addr_t curr_pc = m_state.gpr.r[15];
+ uint32_t curr_cpsr = m_state.gpr.__cpsr;
+ lldb::addr_t next_pc = curr_pc;
+
+ bool curr_pc_is_thumb = (m_state.gpr.__cpsr & 0x20) != 0;
+ bool next_pc_is_thumb = curr_pc_is_thumb;
+
+ uint32_t curr_itstate = ((curr_cpsr & 0x6000000) >> 25) | ((curr_cpsr & 0xFC00) >> 8);
+ bool inITBlock = (curr_itstate & 0xF) ? 1 : 0;
+ bool lastInITBlock = ((curr_itstate & 0xF) == 0x8) ? 1 : 0;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: curr_pc=0x%8.8x (%s), curr_itstate=0x%x, inITBlock=%d, lastInITBlock=%d", __FUNCTION__, curr_pc, curr_pc_is_thumb ? "Thumb" : "ARM", curr_itstate, inITBlock, lastInITBlock);
+
+ // If the instruction is not in the IT block, then decode using the Disassembler and compute next_pc
+ if (!inITBlock)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Decoding an instruction NOT in the IT block", __FUNCTION__);
+
+ arm_error_t decodeReturnCode = DecodeInstructionUsingDisassembler(curr_pc, curr_cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ {
+ err = KERN_INVALID_ARGUMENT;
+ LogError("MachThreadContext_arm::SetSingleStepSoftwareBreakpoints: Unable to disassemble instruction at 0x%8.8lx", curr_pc);
+ }
+ }
+ else
+ {
+ next_pc = curr_pc + ((m_last_decode_arm.thumb16b) ? 2 : 4);
+ }
+
+ // Instruction is NOT in the IT block OR
+ if (!inITBlock)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: normal instruction", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else if (inITBlock && !m_last_decode_arm.setsFlags)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: IT instruction that doesn't set flags", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else if (lastInITBlock && m_last_decode_arm.branch)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: IT instruction which last in the IT block and is a branch", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else
+ {
+ // Instruction is in IT block and can modify the CPSR flags
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: IT instruction that sets flags", __FUNCTION__);
+
+ // NOTE: When this point of code is reached, the instruction at curr_pc has already been decoded
+ // inside the function ShouldStop (). Therefore m_last_decode_arm, m_last_decode_thumb
+ // reflect the decoded instruction at curr_pc
+
+ // If we find an instruction inside the IT block which will set/modify the condition flags (NZCV bits in CPSR),
+ // we set breakpoints at all remaining instructions inside the IT block starting from the instruction immediately
+ // following this one AND a breakpoint at the instruction immediately following the IT block. We do this because
+ // we cannot determine the next_pc until the instruction at which we are currently stopped executes. Hence we
+ // insert (m_last_decode_thumb.itBlockRemaining+1) 16-bit Thumb breakpoints at consecutive memory locations
+ // starting at addrOfNextInstructionInITBlock. We record these breakpoints in class variable m_sw_single_step_itblock_break_id[],
+ // and also record the total number of IT breakpoints set in the variable 'm_sw_single_step_itblock_break_count'.
+
+ // The instructions inside the IT block, which are replaced by the 16-bit Thumb breakpoints (opcode=0xDEFE)
+ // instructions, can be either Thumb-16 or Thumb-32. When a Thumb-32 instruction (say, inst#1) is replaced Thumb
+ // by a 16-bit breakpoint (OS only supports 16-bit breakpoints in Thumb mode and 32-bit breakpoints in ARM mode), the
+ // breakpoint for the next instruction (say instr#2) is saved in the upper half of this Thumb-32 (instr#1)
+ // instruction. Hence if the execution stops at Breakpoint2 corresponding to instr#2, the PC is offset by 16-bits.
+ // We therefore have to keep track of PC of each instruction in the IT block that is being replaced with the 16-bit
+ // Thumb breakpoint, to ensure that when the breakpoint is hit, the PC is adjusted to the correct value. We save
+ // the actual PC corresponding to each instruction in the IT block by associating a call back with each breakpoint
+ // we set and passing it as a baton. When the breakpoint hits and the callback routine is called, the routine
+ // adjusts the PC based on the baton that is passed to it.
+
+ lldb::addr_t addrOfNextInstructionInITBlock, pcInITBlock, nextPCInITBlock, bpAddressInITBlock;
+ uint16_t opcode16;
+ uint32_t opcode32;
+
+ addrOfNextInstructionInITBlock = (m_last_decode_arm.thumb16b) ? curr_pc + 2 : curr_pc + 4;
+
+ pcInITBlock = addrOfNextInstructionInITBlock;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: itBlockRemaining=%d", __FUNCTION__, m_last_decode_thumb.itBlockRemaining);
+
+ m_sw_single_step_itblock_break_count = 0;
+ for (int i = 0; i <= m_last_decode_thumb.itBlockRemaining; i++)
+ {
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ {
+ LogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Array m_sw_single_step_itblock_break_id should not contain any valid breakpoint IDs at this point. But found a valid breakID=%d at index=%d", m_sw_single_step_itblock_break_id[i], i);
+ }
+ else
+ {
+ nextPCInITBlock = pcInITBlock;
+ // Compute nextPCInITBlock based on opcode present at pcInITBlock
+ if (m_thread.Process()->Task().ReadMemory(pcInITBlock, 2, &opcode16) == 2)
+ {
+ opcode32 = opcode16;
+ nextPCInITBlock += 2;
+
+ // Check for 32 bit thumb opcode and read the upper 16 bits if needed
+ if (((opcode32 & 0xE000) == 0xE000) && (opcode32 & 0x1800))
+ {
+ // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for
+ // a 32 bit Thumb opcode
+ // Read bits 31:16 of a 32 bit Thumb opcode
+ if (m_thread.Process()->Task().ReadMemory(pcInITBlock+2, 2, &opcode16) == 2)
+ {
+ // 32 bit thumb opcode
+ opcode32 = (opcode32 << 16) | opcode16;
+ nextPCInITBlock += 2;
+ }
+ else
+ {
+ LogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8lx", nextPCInITBlock);
+ }
+ }
+ }
+ else
+ {
+ LogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Error reading 16-bit Thumb instruction at pc=0x%8.8x", nextPCInITBlock);
+ }
+
+
+ // Set breakpoint and associate a callback function with it
+ bpAddressInITBlock = addrOfNextInstructionInITBlock + 2*i;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Setting IT breakpoint[%d] at address: 0x%8.8x", __FUNCTION__, i, bpAddressInITBlock);
+
+ m_sw_single_step_itblock_break_id[i] = m_thread.Process()->CreateBreakpoint(bpAddressInITBlock, 2, false, m_thread.GetID());
+ if (!LLDB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ err = KERN_INVALID_ARGUMENT;
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: Set IT breakpoint[%i]=%d set at 0x%8.8x for instruction at 0x%8.8x", __FUNCTION__, i, m_sw_single_step_itblock_break_id[i], bpAddressInITBlock, pcInITBlock);
+
+ // Set the breakpoint callback for these special IT breakpoints
+ // so that if one of these breakpoints gets hit, it knows to
+ // update the PC to the original address of the conditional
+ // IT instruction.
+ PDBreakpointSetCallback(m_thread.ProcessID(), m_sw_single_step_itblock_break_id[i], MachThreadContext_arm::BreakpointHit, (void*)pcInITBlock);
+ m_sw_single_step_itblock_break_count++;
+ }
+ }
+
+ pcInITBlock = nextPCInITBlock;
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Set %u IT software single breakpoints.", __FUNCTION__, m_sw_single_step_itblock_break_count);
+
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: next_pc=0x%8.8x (%s)", __FUNCTION__, next_pc, next_pc_is_thumb ? "Thumb" : "ARM");
+
+ if (next_pc & 0x1)
+ {
+ assert(next_pc_is_thumb);
+ }
+
+ if (next_pc_is_thumb)
+ {
+ next_pc &= ~0x1;
+ }
+ else
+ {
+ assert((next_pc & 0x3) == 0);
+ }
+
+ if (!inITBlock || (inITBlock && !m_last_decode_arm.setsFlags) || (lastInITBlock && m_last_decode_arm.branch))
+ {
+ err = KERN_SUCCESS;
+
+#if defined DNB_ARCH_MACH_ARM_DEBUG_SW_STEP
+ m_sw_single_step_next_pc = next_pc;
+ if (next_pc_is_thumb)
+ m_sw_single_step_next_pc |= 1; // Set bit zero if the next PC is expected to be Thumb
+#else
+ const DNBBreakpoint *bp = m_thread.Process()->Breakpoints().FindByAddress(next_pc);
+
+ if (bp == NULL)
+ {
+ m_sw_single_step_break_id = m_thread.Process()->CreateBreakpoint(next_pc, next_pc_is_thumb ? 2 : 4, false, m_thread.GetID());
+ if (!LLDB_BREAK_ID_IS_VALID(m_sw_single_step_break_id))
+ err = KERN_INVALID_ARGUMENT;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: software single step breakpoint with breakID=%d set at 0x%8.8x", __FUNCTION__, m_sw_single_step_break_id, next_pc);
+ }
+#endif
+ }
+
+ return err.GetError();
+}
+
+#endif
+
+MachThreadContext*
+MachThreadContext_arm::Create (const ArchSpec &arch_spec, ThreadMacOSX &thread)
+{
+ return new MachThreadContext_arm(thread);
+}
+
+void
+MachThreadContext_arm::Initialize()
+{
+ ArchSpec arch_spec(CPU_TYPE_ARM, CPU_TYPE_ANY);
+ ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_arm::Create);
+}
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.h
new file mode 100644
index 0000000..4ec72df
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.h
@@ -0,0 +1,63 @@
+//===-- MachThreadContext_arm.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_MachThreadContext_arm_h_
+#define liblldb_MachThreadContext_arm_h_
+
+#include "MachThreadContext.h"
+#include "RegisterContextMach_arm.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext_arm : public MachThreadContext
+{
+public:
+ enum { kMaxNumThumbITBreakpoints = 4 };
+
+ static MachThreadContext*
+ Create (const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ static void
+ Initialize();
+
+ MachThreadContext_arm(ThreadMacOSX &thread);
+
+ virtual
+ ~MachThreadContext_arm();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const;
+
+ virtual void
+ InitializeInstance();
+
+ virtual void
+ ThreadWillResume ();
+
+ virtual bool
+ ShouldStop ();
+
+ virtual void
+ RefreshStateAfterStop ();
+
+ static uint32_t
+ GetCPUType ();
+
+protected:
+ kern_return_t
+ EnableHardwareSingleStep (bool enable);
+
+protected:
+ lldb::addr_t m_hw_single_chained_step_addr;
+ uint32_t m_bvr0_reg;
+ uint32_t m_bcr0_reg;
+ uint32_t m_bvr0_save;
+ uint32_t m_bcr0_save;
+};
+#endif // #ifndef liblldb_MachThreadContext_arm_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.cpp b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.cpp
new file mode 100644
index 0000000..ea148a6
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.cpp
@@ -0,0 +1,245 @@
+//===-- MachThreadContext_i386.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__i386__) || defined (__x86_64__)
+
+
+#include "MachThreadContext_i386.h"
+
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+
+#include "ProcessMacOSX.h"
+#include "ThreadMacOSX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MachThreadContext_i386::MachThreadContext_i386 (ThreadMacOSX &thread) :
+ MachThreadContext (thread),
+ m_flags_reg(LLDB_INVALID_REGNUM)
+{
+}
+
+MachThreadContext_i386::~MachThreadContext_i386()
+{
+}
+
+
+MachThreadContext*
+MachThreadContext_i386::Create (const ArchSpec &arch_spec, ThreadMacOSX &thread)
+{
+ return new MachThreadContext_i386(thread);
+}
+
+// Class init function
+void
+MachThreadContext_i386::Initialize()
+{
+ ArchSpec arch_spec("i386");
+ ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_i386::Create);
+}
+
+// Instance init function
+void
+MachThreadContext_i386::InitializeInstance()
+{
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx != NULL);
+ m_flags_reg = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+}
+
+
+uint32_t
+MachThreadContext_i386::GetCPUType()
+{
+ return CPU_TYPE_I386;
+}
+
+void
+MachThreadContext_i386::ThreadWillResume()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (m_thread.GetState() == eStateStepping);
+}
+
+bool
+MachThreadContext_i386::ShouldStop()
+{
+ return true;
+}
+
+void
+MachThreadContext_i386::RefreshStateAfterStop()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (false);
+}
+
+bool
+MachThreadContext_i386::NotifyException (MachException::Data& exc)
+{
+ switch (exc.exc_type)
+ {
+ case EXC_BAD_ACCESS:
+ break;
+ case EXC_BAD_INSTRUCTION:
+ break;
+ case EXC_ARITHMETIC:
+ break;
+ case EXC_EMULATION:
+ break;
+ case EXC_SOFTWARE:
+ break;
+ case EXC_BREAKPOINT:
+ if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
+ {
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+ lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
+ if (pc != LLDB_INVALID_ADDRESS && pc > 0)
+ {
+ pc -= 1;
+ reg_ctx->SetPC(pc);
+ }
+ return true;
+ }
+ break;
+ case EXC_SYSCALL:
+ break;
+ case EXC_MACH_SYSCALL:
+ break;
+ case EXC_RPC_ALERT:
+ break;
+ }
+ return false;
+}
+
+
+// Set the single step bit in the processor status register.
+//kern_return_t
+//MachThreadContext_i386::EnableHardwareSingleStep (bool enable)
+//{
+// RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+// assert (reg_ctx);
+// Scalar rflags_scalar;
+//
+// if (reg_ctx->ReadRegisterValue (m_flags_reg, rflags_scalar))
+// {
+// Flags rflags(rflags_scalar.UInt());
+// const uint32_t trace_bit = 0x100u;
+// if (enable)
+// {
+// // If the trace bit is already cleared, there is nothing to do
+// if (rflags.IsSet (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Set (trace_bit);
+// }
+// else
+// {
+// // If the trace bit is already cleared, there is nothing to do
+// if (rflags.IsClear (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Clear(trace_bit);
+// }
+//
+// rflags_scalar = rflags.GetAllFlagBits();
+// // If the code makes it here we have changes to the GPRs which
+// // we need to write back out, so lets do that.
+// if (reg_ctx->WriteRegisterValue(m_flags_reg, rflags_scalar))
+// return KERN_SUCCESS;
+// }
+// // Return the error code for reading the GPR registers back
+// return KERN_INVALID_ARGUMENT;
+//}
+
+RegisterContext *
+MachThreadContext_i386::CreateRegisterContext (StackFrame *frame) const
+{
+ return new RegisterContextMach_i386(m_thread, frame);
+}
+
+
+size_t
+MachThreadContext_i386::GetStackFrameData(StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
+{
+ fp_pc_pairs.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);
+
+ Frame_i386 frame = { reg_ctx->GetFP(0), reg_ctx->GetPC(LLDB_INVALID_ADDRESS) };
+
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+
+ 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 != 0)
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+ }
+ if (!fp_pc_pairs.empty())
+ {
+ lldb::addr_t first_frame_pc = fp_pc_pairs.front().second;
+ 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))
+ {
+ // Construct a correct second frame (we already read the pc for it above
+ frame.fp = fp_pc_pairs.front().first;
+
+ // Insert the frame
+ fp_pc_pairs.insert(fp_pc_pairs.begin()+1, std::make_pair(frame.fp, frame.pc));
+
+ // Correct the fp in the first frame to use the SP
+ fp_pc_pairs.front().first = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return fp_pc_pairs.size();
+}
+
+
+#endif // #if defined (__i386__)
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.h
new file mode 100644
index 0000000..4bee2e7
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.h
@@ -0,0 +1,57 @@
+//===-- MachThreadContext_i386.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_MachThreadContext_i386_h_
+#define liblldb_MachThreadContext_i386_h_
+
+#if defined (__i386__) || defined (__x86_64__)
+
+#include "MachThreadContext.h"
+#include "RegisterContextMach_i386.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext_i386 : public MachThreadContext
+{
+public:
+ static MachThreadContext* Create(const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ // Class init function
+ static void Initialize();
+
+ MachThreadContext_i386(ThreadMacOSX &thread);
+
+ virtual
+ ~MachThreadContext_i386();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const;
+
+ virtual void InitializeInstance();
+ virtual void ThreadWillResume();
+ virtual bool ShouldStop ();
+ virtual void RefreshStateAfterStop();
+
+ virtual bool NotifyException(MachException::Data& exc);
+ virtual size_t GetStackFrameData(lldb_private::StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
+ static uint32_t GetCPUType();
+
+protected:
+// kern_return_t EnableHardwareSingleStep (bool enable);
+ uint32_t m_flags_reg;
+private:
+ DISALLOW_COPY_AND_ASSIGN (MachThreadContext_i386);
+};
+
+//#if defined (__i386__)
+//typedef MachThreadContext_i386 DNBArch;
+//#endif
+
+#endif // defined (__i386__) || defined (__x86_64__)
+#endif // #ifndef liblldb_MachThreadContext_i386_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.cpp b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.cpp
new file mode 100644
index 0000000..3ee9eb4
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.cpp
@@ -0,0 +1,255 @@
+//===-- MachThreadContext_x86_64.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__i386__) || defined (__x86_64__)
+
+#include <sys/cdefs.h>
+
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+
+#include "MachThreadContext_x86_64.h"
+#include "ProcessMacOSX.h"
+#include "ThreadMacOSX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MachThreadContext_x86_64::MachThreadContext_x86_64(ThreadMacOSX &thread) :
+ MachThreadContext (thread),
+ m_flags_reg(LLDB_INVALID_REGNUM)
+{
+}
+
+MachThreadContext_x86_64::~MachThreadContext_x86_64()
+{
+}
+
+MachThreadContext*
+MachThreadContext_x86_64::Create(const ArchSpec &arch_spec, ThreadMacOSX &thread)
+{
+ return new MachThreadContext_x86_64(thread);
+}
+
+// Class init function
+void
+MachThreadContext_x86_64::Initialize()
+{
+ ArchSpec arch_spec("x86_64");
+ ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_x86_64::Create);
+}
+
+// Instance init function
+void
+MachThreadContext_x86_64::InitializeInstance()
+{
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx != NULL);
+ m_flags_reg = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+}
+
+uint32_t
+MachThreadContext_x86_64::GetCPUType()
+{
+ return CPU_TYPE_X86_64;
+}
+
+void
+MachThreadContext_x86_64::ThreadWillResume()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (m_thread.GetState() == eStateStepping);
+}
+
+bool
+MachThreadContext_x86_64::ShouldStop()
+{
+ return true;
+}
+
+void
+MachThreadContext_x86_64::RefreshStateAfterStop()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (false);
+}
+
+bool
+MachThreadContext_x86_64::NotifyException(MachException::Data& exc)
+{
+ switch (exc.exc_type)
+ {
+ case EXC_BAD_ACCESS:
+ break;
+ case EXC_BAD_INSTRUCTION:
+ break;
+ case EXC_ARITHMETIC:
+ break;
+ case EXC_EMULATION:
+ break;
+ case EXC_SOFTWARE:
+ break;
+ case EXC_BREAKPOINT:
+ if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
+ {
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+ lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
+ if (pc != LLDB_INVALID_ADDRESS && pc > 0)
+ {
+ pc -= 1;
+ reg_ctx->SetPC(pc);
+ }
+ return true;
+ }
+ break;
+ case EXC_SYSCALL:
+ break;
+ case EXC_MACH_SYSCALL:
+ break;
+ case EXC_RPC_ALERT:
+ break;
+ }
+ return false;
+}
+
+
+// Set the single step bit in the processor status register.
+//kern_return_t
+//MachThreadContext_x86_64::EnableHardwareSingleStep (bool enable)
+//{
+// RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+// assert (reg_ctx);
+// Scalar rflags_scalar;
+//
+// if (reg_ctx->ReadRegisterValue (m_flags_reg, rflags_scalar))
+// {
+// Flags rflags(rflags_scalar.UInt());
+// const uint32_t trace_bit = 0x100u;
+// if (enable)
+// {
+// // If the trace bit is already set, there is nothing to do
+// if (rflags.IsSet (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Set (trace_bit);
+// }
+// else
+// {
+// // If the trace bit is already cleared, there is nothing to do
+// if (rflags.IsClear (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Clear(trace_bit);
+// }
+//
+// rflags_scalar = rflags.GetAllFlagBits();
+// // If the code makes it here we have changes to the GPRs which
+// // we need to write back out, so lets do that.
+// if (reg_ctx->WriteRegisterValue(m_flags_reg, rflags_scalar))
+// return KERN_SUCCESS;
+// }
+// // Return the error code for reading the GPR registers back
+// return KERN_INVALID_ARGUMENT;
+//}
+//
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit PowerPC.
+//----------------------------------------------------------------------
+
+
+
+RegisterContext *
+MachThreadContext_x86_64::CreateRegisterContext (StackFrame *frame) const
+{
+ return new RegisterContextMach_x86_64(m_thread, frame);
+}
+
+
+//bool
+//MachThreadContext_x86_64::RegisterSetStateIsValid (uint32_t set) const
+//{
+// return m_state.RegisterSetIsCached(set);
+//}
+
+
+size_t
+MachThreadContext_x86_64::GetStackFrameData(StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
+{
+ fp_pc_pairs.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);
+
+ Frame_x86_64 frame = { reg_ctx->GetFP(0), reg_ctx->GetPC(LLDB_INVALID_ADDRESS) };
+
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+ 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)
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+ }
+ if (!fp_pc_pairs.empty())
+ {
+ lldb::addr_t first_frame_pc = fp_pc_pairs.front().second;
+ 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))
+ {
+ // Construct a correct second frame (we already read the pc for it above
+ frame.fp = fp_pc_pairs.front().first;
+
+ // Insert the frame
+ fp_pc_pairs.insert(fp_pc_pairs.begin()+1, std::make_pair(frame.fp, frame.pc));
+
+ // Correct the fp in the first frame to use the SP
+ fp_pc_pairs.front().first = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return fp_pc_pairs.size();
+}
+
+
+#endif // #if defined (__i386__) || defined (__x86_64__)
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.h
new file mode 100644
index 0000000..45d5a37
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.h
@@ -0,0 +1,72 @@
+//===-- MachThreadContext_x86_64.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_MachThreadContext_x86_64_h_
+#define liblldb_MachThreadContext_x86_64_h_
+
+#if defined (__i386__) || defined (__x86_64__)
+
+#include "MachThreadContext.h"
+#include "RegisterContextMach_x86_64.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext_x86_64 : public MachThreadContext
+{
+public:
+ static MachThreadContext*
+ Create(const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ // Class init function
+ static void
+ Initialize();
+
+ // Instance init function
+ void
+ InitializeInstance();
+
+ MachThreadContext_x86_64 (ThreadMacOSX &thread);
+
+ virtual
+ ~MachThreadContext_x86_64();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const;
+
+ virtual void
+ ThreadWillResume ();
+
+ virtual bool
+ ShouldStop ();
+
+ virtual void
+ RefreshStateAfterStop ();
+
+ virtual bool
+ NotifyException (MachException::Data& exc);
+
+ virtual size_t
+ GetStackFrameData (lldb_private::StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
+
+ static uint32_t
+ GetCPUType();
+
+protected:
+// kern_return_t EnableHardwareSingleStep (bool enable);
+ uint32_t m_flags_reg;
+private:
+ DISALLOW_COPY_AND_ASSIGN (MachThreadContext_x86_64);
+};
+
+//#if defined (__x86_64__)
+//typedef MachThreadContext_x86_64 DNBArch;
+//#endif
+
+#endif // defined (__i386__) || defined (__x86_64__)
+#endif // #ifndef liblldb_MachThreadContext_x86_64_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.cpp b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.cpp
new file mode 100644
index 0000000..c91af3c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.cpp
@@ -0,0 +1,195 @@
+//===-- MachVMMemory.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachVMMemory.h"
+
+#include <mach/mach_vm.h>
+
+#include "MachVMRegion.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb_private;
+
+MachVMMemory::MachVMMemory() :
+ m_page_size (kInvalidPageSize)
+{
+}
+
+MachVMMemory::~MachVMMemory()
+{
+}
+
+size_t
+MachVMMemory::PageSize(lldb_private::Error &error)
+{
+ if (m_page_size == kInvalidPageSize)
+ {
+ error = ::host_page_size( ::mach_host_self(), &m_page_size);
+ if (error.Fail())
+ m_page_size = 0;
+ }
+
+ if (m_page_size != 0 && m_page_size != kInvalidPageSize)
+ {
+ if (error.Success())
+ error.SetErrorString ("unable to determine page size");
+ }
+ return m_page_size;
+}
+
+size_t
+MachVMMemory::MaxBytesLeftInPage (lldb::addr_t addr, size_t count)
+{
+ Error error;
+ const size_t page_size = PageSize(error);
+ if (page_size > 0)
+ {
+ size_t page_offset = (addr % page_size);
+ size_t bytes_left_in_page = page_size - page_offset;
+ if (count > bytes_left_in_page)
+ count = bytes_left_in_page;
+ }
+ return count;
+}
+
+size_t
+MachVMMemory::Read(task_t task, lldb::addr_t address, void *data, size_t data_count, Error &error)
+{
+ if (data == NULL || data_count == 0)
+ return 0;
+
+ size_t total_bytes_read = 0;
+ lldb::addr_t curr_addr = address;
+ uint8_t *curr_data = (uint8_t*)data;
+ while (total_bytes_read < data_count)
+ {
+ mach_vm_size_t curr_size = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_read);
+ mach_msg_type_number_t curr_bytes_read = 0;
+ vm_offset_t vm_memory = NULL;
+ error = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY|PD_LOG_VERBOSE);
+
+ if (log || error.Fail())
+ error.PutToLog (log, "::mach_vm_read (task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt => %i)", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read);
+
+ if (error.Success())
+ {
+ if (curr_bytes_read != curr_size)
+ {
+ if (log)
+ error.PutToLog (log, "::mach_vm_read (task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt=>%i) only read %u of %llu bytes", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read, curr_bytes_read, (uint64_t)curr_size);
+ }
+ ::memcpy (curr_data, (void *)vm_memory, curr_bytes_read);
+ ::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read);
+ total_bytes_read += curr_bytes_read;
+ curr_addr += curr_bytes_read;
+ curr_data += curr_bytes_read;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return total_bytes_read;
+}
+
+
+size_t
+MachVMMemory::Write(task_t task, lldb::addr_t address, const void *data, size_t data_count, Error &error)
+{
+ MachVMRegion vmRegion(task);
+
+ size_t total_bytes_written = 0;
+ lldb::addr_t curr_addr = address;
+ const uint8_t *curr_data = (const uint8_t*)data;
+
+
+ while (total_bytes_written < data_count)
+ {
+ if (vmRegion.GetRegionForAddress(curr_addr))
+ {
+ mach_vm_size_t curr_data_count = data_count - total_bytes_written;
+ mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr);
+ if (region_bytes_left == 0)
+ {
+ break;
+ }
+ if (curr_data_count > region_bytes_left)
+ curr_data_count = region_bytes_left;
+
+ if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE))
+ {
+ size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count, error);
+ if (bytes_written <= 0)
+ {
+ // Error should have already be posted by WriteRegion...
+ break;
+ }
+ else
+ {
+ total_bytes_written += bytes_written;
+ curr_addr += bytes_written;
+ curr_data += bytes_written;
+ }
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on region for address: [0x%8.8llx-0x%8.8llx)", (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count));
+ break;
+ }
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address);
+ break;
+ }
+ }
+
+ return total_bytes_written;
+}
+
+
+size_t
+MachVMMemory::WriteRegion(task_t task, const lldb::addr_t address, const void *data, const size_t data_count, Error &error)
+{
+ if (data == NULL || data_count == 0)
+ return 0;
+
+ size_t total_bytes_written = 0;
+ lldb::addr_t curr_addr = address;
+ const uint8_t *curr_data = (const uint8_t*)data;
+ while (total_bytes_written < data_count)
+ {
+ mach_msg_type_number_t curr_data_count = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_written);
+ error = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+ if (log || error.Fail())
+ error.PutToLog (log, "::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, data = %8.8p, dataCnt = %u )", task, (uint64_t)curr_addr, curr_data, curr_data_count);
+
+#if defined (__powerpc__) || defined (__ppc__)
+ vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH;
+
+ error = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value);
+ if (log || error.Fail())
+ error.Log(log, "::vm_machine_attribute ( task = 0x%4.4x, addr = 0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value => MATTR_VAL_CACHE_FLUSH )", task, (uint64_t)curr_addr, curr_data_count);
+#endif
+
+ if (error.Success())
+ {
+ total_bytes_written += curr_data_count;
+ curr_addr += curr_data_count;
+ curr_data += curr_data_count;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return total_bytes_written;
+}
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.h
new file mode 100644
index 0000000..866fa36
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.h
@@ -0,0 +1,36 @@
+//===-- MachVMMemory.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_MachVMMemory_h_
+#define liblldb_MachVMMemory_h_
+
+#include <mach/mach.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+
+class MachVMMemory
+{
+public:
+ enum { kInvalidPageSize = ~0 };
+ MachVMMemory();
+ ~MachVMMemory();
+ size_t Read(task_t task, lldb::addr_t address, void *data, size_t data_count, lldb_private::Error &error);
+ size_t Write(task_t task, lldb::addr_t address, const void *data, size_t data_count, lldb_private::Error &error);
+ size_t PageSize(lldb_private::Error &error);
+
+protected:
+ size_t MaxBytesLeftInPage(lldb::addr_t addr, size_t count);
+
+ size_t WriteRegion(task_t task, const lldb::addr_t address, const void *data, const size_t data_count, lldb_private::Error &error);
+ vm_size_t m_page_size;
+};
+
+
+#endif // #ifndef liblldb_MachVMMemory_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.cpp b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.cpp
new file mode 100644
index 0000000..87044fb
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.cpp
@@ -0,0 +1,183 @@
+//===-- MachVMRegion.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <mach/mach_vm.h>
+#include "MachVMRegion.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb_private;
+
+MachVMRegion::MachVMRegion(task_t task) :
+ m_task(task),
+ m_addr(LLDB_INVALID_ADDRESS),
+ m_err(),
+ m_start(LLDB_INVALID_ADDRESS),
+ m_size(0),
+ m_depth(-1),
+ m_data(),
+ m_curr_protection(0),
+ m_protection_addr(LLDB_INVALID_ADDRESS),
+ m_protection_size(0)
+{
+ memset(&m_data, 0, sizeof(m_data));
+}
+
+MachVMRegion::~MachVMRegion()
+{
+ // Restore any original protections and clear our vars
+ Clear();
+}
+
+void
+MachVMRegion::Clear()
+{
+ RestoreProtections();
+ m_addr = LLDB_INVALID_ADDRESS;
+ m_err.Clear();
+ m_start = LLDB_INVALID_ADDRESS;
+ m_size = 0;
+ m_depth = -1;
+ memset(&m_data, 0, sizeof(m_data));
+ m_curr_protection = 0;
+ m_protection_addr = LLDB_INVALID_ADDRESS;
+ m_protection_size = 0;
+}
+
+bool
+MachVMRegion::SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot)
+{
+ if (ContainsAddress(addr))
+ {
+ mach_vm_size_t prot_size = size;
+ mach_vm_address_t end_addr = EndAddress();
+ if (prot_size > (end_addr - addr))
+ prot_size = end_addr - addr;
+
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS);
+ if (prot_size > 0)
+ {
+ if (prot == (m_curr_protection & VM_PROT_ALL))
+ {
+ if (log)
+ log->Printf ("MachVMRegion::%s: protections (%u) already sufficient for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, prot, m_task, (uint64_t)addr);
+ // Protections are already set as requested...
+ return true;
+ }
+ else
+ {
+ m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot);
+ if (m_err.Fail())
+ {
+ // Try again with the ability to create a copy on write region
+ m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot | VM_PROT_COPY);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot | VM_PROT_COPY);
+ }
+ if (m_err.Success())
+ {
+ m_curr_protection = prot;
+ m_protection_addr = addr;
+ m_protection_size = prot_size;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ log->Printf("MachVMRegion::%s: Zero size for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, m_task, (uint64_t)addr);
+ }
+ }
+ return false;
+}
+
+bool
+MachVMRegion::RestoreProtections()
+{
+ if (m_curr_protection != m_data.protection && m_protection_size > 0)
+ {
+ m_err = ::mach_vm_protect (m_task, m_protection_addr, m_protection_size, 0, m_data.protection);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)m_protection_addr, (uint64_t)m_protection_size, 0, m_data.protection);
+ if (m_err.Success())
+ {
+ m_protection_size = 0;
+ m_protection_addr = LLDB_INVALID_ADDRESS;
+ m_curr_protection = m_data.protection;
+ return true;
+ }
+ }
+ else
+ {
+ m_err.Clear();
+ return true;
+ }
+
+ return false;
+}
+
+bool
+MachVMRegion::GetRegionForAddress(lldb::addr_t addr)
+{
+ // Restore any original protections and clear our vars
+ Clear();
+ m_addr = addr;
+ m_start = addr;
+ m_depth = 1024;
+ mach_msg_type_number_t info_size = kRegionInfoSize;
+ assert(sizeof(info_size) == 4);
+ m_err = ::mach_vm_region_recurse (m_task, &m_start, &m_size, &m_depth, (vm_region_recurse_info_t)&m_data, &info_size);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_region_recurse ( task = 0x%4.4x, address => 0x%8.8llx, size => %llu, nesting_depth => %d, info => %p, infoCnt => %d) addr = 0x%8.8llx ", m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, &m_data, info_size, (uint64_t)addr);
+ if (m_err.Fail())
+ {
+ return false;
+ }
+ else
+ {
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ {
+ log->Printf("info = { prot = %u, "
+ "max_prot = %u, "
+ "inheritance = 0x%8.8x, "
+ "offset = 0x%8.8llx, "
+ "user_tag = 0x%8.8x, "
+ "ref_count = %u, "
+ "shadow_depth = %u, "
+ "ext_pager = %u, "
+ "share_mode = %u, "
+ "is_submap = %d, "
+ "behavior = %d, "
+ "object_id = 0x%8.8x, "
+ "user_wired_count = 0x%4.4x }",
+ m_data.protection,
+ m_data.max_protection,
+ m_data.inheritance,
+ (uint64_t)m_data.offset,
+ m_data.user_tag,
+ m_data.ref_count,
+ m_data.shadow_depth,
+ m_data.external_pager,
+ m_data.share_mode,
+ m_data.is_submap,
+ m_data.behavior,
+ m_data.object_id,
+ m_data.user_wired_count);
+ }
+ }
+
+ m_curr_protection = m_data.protection;
+
+ return true;
+}
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.h b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.h
new file mode 100644
index 0000000..b12353d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.h
@@ -0,0 +1,63 @@
+//===-- MachVMRegion.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_MachVMRegion_h_
+#define liblldb_MachVMRegion_h_
+
+#include <mach/mach.h>
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+
+class MachVMRegion
+{
+public:
+ MachVMRegion(task_t task);
+ ~MachVMRegion();
+
+ void Clear();
+ mach_vm_address_t StartAddress() const { return m_start; }
+ mach_vm_address_t EndAddress() const { return m_start + m_size; }
+ mach_vm_address_t BytesRemaining(mach_vm_address_t addr) const
+ {
+ if (ContainsAddress(addr))
+ return m_size - (addr - m_start);
+ else
+ return 0;
+ }
+ bool ContainsAddress(mach_vm_address_t addr) const
+ {
+ return addr >= StartAddress() && addr < EndAddress();
+ }
+
+ bool SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot);
+ bool RestoreProtections();
+ bool GetRegionForAddress(lldb::addr_t addr);
+protected:
+#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64)
+ typedef vm_region_submap_short_info_data_64_t RegionInfo;
+ enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
+#else
+ typedef vm_region_submap_info_data_64_t RegionInfo;
+ enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 };
+#endif
+
+ task_t m_task;
+ mach_vm_address_t m_addr;
+ lldb_private::Error m_err;
+ mach_vm_address_t m_start;
+ mach_vm_size_t m_size;
+ natural_t m_depth;
+ RegionInfo m_data;
+ vm_prot_t m_curr_protection; // The current, possibly modified protections. Original value is saved in m_data.protections.
+ mach_vm_address_t m_protection_addr; // The start address at which protections were changed
+ mach_vm_size_t m_protection_size; // The size of memory that had its protections changed
+
+};
+
+#endif // #ifndef liblldb_MachVMRegion_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/MacOSX/ProcessControl-mig.defs b/source/Plugins/Process/MacOSX-User/source/MacOSX/ProcessControl-mig.defs
new file mode 100644
index 0000000..7f16fe1
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/MacOSX/ProcessControl-mig.defs
@@ -0,0 +1,16 @@
+/*
+ * nub.defs
+ */
+
+/*
+ * DNBConfig.h is autogenerated by a perl script that is run as a build
+ * script in XCode. XCode is responsible for calling the script and setting
+ * the include paths correctly to locate it. The file will exist in the
+ * derived sources directory in the build folder.
+ *
+ */
+
+#include "DNBConfig.h"
+
+
+#include <mach/mach_exc.defs>
diff --git a/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp
new file mode 100644
index 0000000..3c37b64
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp
@@ -0,0 +1,2228 @@
+//===-- ProcessMacOSX.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
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <spawn.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <algorithm>
+#include <map>
+
+// Other libraries and framework includes
+
+#include "lldb/Breakpoint/WatchpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "PseudoTerminal.h"
+
+#if defined (__arm__)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SpringBoardServices/SpringBoardServer.h>
+#include <SpringBoardServices/SBSWatchdogAssertion.h>
+
+#endif // #if defined (__arm__)
+
+// Project includes
+#include "lldb/Host/Host.h"
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+#include "ThreadMacOSX.h"
+
+
+#if 0
+#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_LOG(fmt, ...)
+#endif
+
+#ifndef MACH_PROCESS_USE_POSIX_SPAWN
+#define MACH_PROCESS_USE_POSIX_SPAWN 1
+#endif
+
+
+#if defined (__arm__)
+
+static bool
+IsSBProcess (lldb::pid_t pid)
+{
+ bool opt_runningApps = true;
+ bool opt_debuggable = false;
+
+ CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
+ if (sbsAppIDs.get() != NULL)
+ {
+ CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
+ CFIndex i = 0;
+ for (i = 0; i < count; i++)
+ {
+ CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
+
+ // Get the process id for the app (if there is one)
+ lldb::pid_t sbs_pid = LLDB_INVALID_PROCESS_ID;
+ if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
+ {
+ if (sbs_pid == pid)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+#endif // #if defined (__arm__)
+
+using namespace lldb;
+using namespace lldb_private;
+//
+//void *
+//ProcessMacOSX::WaitForChildProcessToExit (void *pid_ptr)
+//{
+// const lldb::pid_t pid = *((lldb::user_id_t *)pid_ptr);
+//
+// Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+//
+// if (log)
+// log->Printf ("ProcessMacOSX::%s (arg = %p) thread starting...", __FUNCTION__, pid_ptr);
+//
+// int status = -1;
+//
+// while (1)
+// {
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0)...", pid, &status);
+//
+// lldb::pid_t return_pid = ::waitpid (pid, &status, 0);
+//
+// if (return_pid < 0)
+// {
+// if (log)
+// log->Printf("%s ::waitpid (pid = %i, stat_loc = %p, options = 0) => errno = %i, status = 0x%8.8x", pid, &status, errno, status);
+// break;
+// }
+//
+// bool set_exit_status = false;
+// if (WIFSTOPPED(status))
+// {
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x (STOPPED)", pid, &status, return_pid, status);
+// }
+// else if (WIFEXITED(status))
+// {
+// set_exit_status = true;
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x (EXITED)", pid, &status, return_pid, status);
+// }
+// else if (WIFSIGNALED(status))
+// {
+// set_exit_status = true;
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x (SIGNALED)", pid, &status, return_pid, status);
+// }
+// else
+// {
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x", pid, &status, return_pid, status);
+// }
+//
+// if (set_exit_status)
+// {
+// // Try and deliver the news to the process if it is still around
+// TargetSP target_sp(TargetList::SharedList().FindTargetWithProcessID (return_pid));
+// if (target_sp.get())
+// {
+// ProcessMacOSX *process = dynamic_cast<ProcessMacOSX*>(target_sp->GetProcess().get());
+// if (process)
+// {
+// process->SetExitStatus (status);
+// if (log)
+// log->Printf("Setting exit status of %i to 0x%8.8x", pid, status);
+// process->Task().ShutDownExceptionThread();
+// }
+// }
+// // Break out of the loop and return.
+// break;
+// }
+// }
+//
+// if (log)
+// log->Printf ("ProcessMacOSX::%s (arg = %p) thread exiting...", __FUNCTION__, pid_ptr);
+//
+// return NULL;
+//}
+//
+
+const char *
+ProcessMacOSX::GetPluginNameStatic()
+{
+ return "process.macosx";
+}
+
+const char *
+ProcessMacOSX::GetPluginDescriptionStatic()
+{
+ return "Native MacOSX user process debugging plug-in.";
+}
+
+void
+ProcessMacOSX::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessMacOSX::CreateInstance);
+}
+
+
+Process*
+ProcessMacOSX::CreateInstance (Target &target, Listener &listener)
+{
+ ProcessMacOSX::Initialize();
+
+ return new ProcessMacOSX (target, listener);
+}
+
+bool
+ProcessMacOSX::CanDebug(Target &target)
+{
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target.GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessMacOSX constructor
+//----------------------------------------------------------------------
+ProcessMacOSX::ProcessMacOSX(Target& target, Listener &listener) :
+ Process (target, listener),
+ m_dynamic_loader_ap (),
+// m_wait_thread (LLDB_INVALID_HOST_THREAD),
+ m_byte_order (eByteOrderHost),
+ m_stdio_ours (false),
+ m_child_stdin (-1),
+ m_child_stdout (-1),
+ m_child_stderr (-1),
+ m_task (this),
+ m_flags (eFlagsNone),
+ m_stdio_thread (LLDB_INVALID_HOST_THREAD),
+ m_stdio_mutex (Mutex::eMutexTypeRecursive),
+ m_stdout_data (),
+ m_exception_messages (),
+ m_exception_messages_mutex (Mutex::eMutexTypeRecursive),
+ m_arch_spec ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessMacOSX::~ProcessMacOSX()
+{
+// m_mach_process.UnregisterNotificationCallbacks (this);
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+const char *
+ProcessMacOSX::GetPluginName()
+{
+ return "Process debugging plug-in for MacOSX";
+}
+
+const char *
+ProcessMacOSX::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessMacOSX::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessMacOSX::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+ strm->Printf("The following arguments can be supplied to the 'log %s' command:\n", GetShortPluginName());
+ strm->PutCString("\tverbose - enable verbose logging\n");
+ strm->PutCString("\tprocess - enable process logging\n");
+ strm->PutCString("\tthread - enable thread logging\n");
+ strm->PutCString("\texceptions - enable exception logging\n");
+ strm->PutCString("\tdynamic - enable DynamicLoader logging\n");
+ strm->PutCString("\tmemory-calls - enable memory read and write call logging\n");
+ strm->PutCString("\tmemory-data-short - log short memory read and write byte data\n");
+ strm->PutCString("\tmemory-data-long - log all memory read and write byte data\n");
+ strm->PutCString("\tmemory-protections - log memory protection calls\n");
+ strm->PutCString("\tbreakpoints - log breakpoint calls\n");
+ strm->PutCString("\twatchpoints - log watchpoint calls\n");
+ strm->PutCString("\tevents - log event and event queue status\n");
+ strm->PutCString("\tstep - log step related activity\n");
+ strm->PutCString("\ttask - log task functions\n");
+}
+
+Error
+ProcessMacOSX::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ProcessMacOSX::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessMacOSX::DoLaunch
+(
+ Module* module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+// ::LogSetBitMask (PD_LOG_DEFAULT);
+// ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+// ::LogSetLogFile ("/dev/stdout");
+
+ Error error;
+ ObjectFile * object_file = module->GetObjectFile();
+ if (object_file)
+ {
+ ArchSpec arch_spec(module->GetArchitecture());
+
+ // Set our user ID to our process ID.
+ SetID (LaunchForDebug(argv[0], argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, eLaunchDefault, error));
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID (LLDB_INVALID_PROCESS_ID);
+ error.SetErrorToGenericError ();
+ error.SetErrorStringWithFormat("Failed to get object file from '%s' for arch %s.\n", module->GetFileSpec().GetFilename().AsCString(), module->GetArchitecture().AsCString());
+ }
+
+ // Return the process ID we have
+ return error;
+}
+
+Error
+ProcessMacOSX::DoAttach (lldb::pid_t attach_pid)
+{
+ Error error;
+
+ // Clear out and clean up from any current state
+ Clear();
+ // HACK: require arch be set correctly at the target level until we can
+ // figure out a good way to determine the arch of what we are attaching to
+ m_arch_spec = m_target.GetArchitecture();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ SetPrivateState (eStateAttaching);
+ SetID(attach_pid);
+ // Let ourselves know we are going to be using SBS if the correct flag bit is set...
+#if defined (__arm__)
+ if (IsSBProcess(pid))
+ m_flags |= eFlagsUsingSBS;
+#endif
+
+ if (Task().GetTaskPortForProcessID(error) == TASK_NULL)
+ {
+ if (log)
+ log->Printf ("error attaching to pid %i: %s", GetID(), error.AsCString());
+
+ }
+ else
+ {
+ Task().StartExceptionThread(error);
+
+ if (error.Success())
+ {
+ errno = 0;
+ if (::ptrace (PT_ATTACHEXC, GetID(), 0, 0) == 0)
+ {
+ m_flags.Set (eFlagsAttached);
+ // Sleep a bit to let the exception get received and set our process status
+ // to stopped.
+ ::usleep(250000);
+
+ if (log)
+ log->Printf ("successfully attached to pid %d", GetID());
+ return error;
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ if (log)
+ log->Printf ("error: failed to attach to pid %d", GetID());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: failed to start exception thread for pid %d: %s", GetID(), error.AsCString());
+ }
+
+ }
+ }
+ SetID (LLDB_INVALID_PROCESS_ID);
+ if (error.Success())
+ error.SetErrorStringWithFormat ("failed to attach to pid %d", attach_pid);
+ return error;
+}
+
+Error
+ProcessMacOSX::WillLaunchOrAttach ()
+{
+ Error error;
+ // TODO: this is hardcoded for macosx right now. We need this to be more dynamic
+ m_dynamic_loader_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.macosx-dyld"));
+
+ if (m_dynamic_loader_ap.get() == NULL)
+ error.SetErrorString("unable to find the dynamic loader named 'dynamic-loader.macosx-dyld'");
+
+ return error;
+}
+
+
+Error
+ProcessMacOSX::WillLaunch (Module* module)
+{
+ return WillLaunchOrAttach ();
+}
+
+void
+ProcessMacOSX::DidLaunchOrAttach ()
+{
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ m_dynamic_loader_ap.reset();
+ }
+ else
+ {
+ Module * exe_module = GetTarget().GetExecutableModule ().get();
+ assert (exe_module);
+
+ m_arch_spec = exe_module->GetArchitecture();
+ assert (m_arch_spec.IsValid());
+
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ assert (exe_objfile);
+
+ m_byte_order = exe_objfile->GetByteOrder();
+ assert (m_byte_order != eByteOrderInvalid);
+ // Install a signal handler so we can catch when our child process
+ // dies and set the exit status correctly.
+
+ Host::StartMonitoringChildProcess (Process::SetProcessExitStatus, NULL, GetID(), false);
+
+ if (m_arch_spec == ArchSpec("arm"))
+ {
+ // On ARM we want the actual target triple of the OS to get the
+ // most capable ARM slice for the process. Since this plug-in is
+ // only used for doing native debugging this will work.
+ m_target_triple = Host::GetTargetTriple();
+ }
+ else
+ {
+ // We want the arch of the process, and the vendor and OS from the
+ // host OS.
+ StreamString triple;
+
+ triple.Printf("%s-%s-%s",
+ m_arch_spec.AsCString(),
+ Host::GetVendorString().AsCString("apple"),
+ Host::GetOSString().AsCString("darwin"));
+
+ m_target_triple.SetCString(triple.GetString().c_str());
+ }
+ }
+}
+
+void
+ProcessMacOSX::DidLaunch ()
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::DidLaunch()");
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidLaunch();
+}
+
+void
+ProcessMacOSX::DidAttach ()
+{
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidAttach();
+}
+
+Error
+ProcessMacOSX::WillAttach (lldb::pid_t pid)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessMacOSX::DoResume ()
+{
+ Error error;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::Resume()");
+ const StateType state = m_private_state.GetValue();
+
+ if (CanResume(state))
+ {
+ error = PrivateResume(LLDB_INVALID_THREAD_ID);
+ }
+ else if (state == eStateRunning)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x is running, ignoring...", Task().GetTaskPort());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("task 0x%x can't continue, ignoring...", Task().GetTaskPort());
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x can't continue, ignoring...", Task().GetTaskPort());
+ }
+ return error;
+}
+
+size_t
+ProcessMacOSX::GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site)
+{
+ const uint8_t *trap_opcode = NULL;
+ uint32_t trap_opcode_size = 0;
+
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ //static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+ static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+
+ switch (m_arch_spec.GetCPUType())
+ {
+ case CPU_TYPE_ARM:
+ // TODO: fill this in for ARM. We need to dig up the symbol for
+ // the address in the breakpoint locaiton and figure out if it is
+ // an ARM or Thumb breakpoint.
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ trap_opcode = g_ppc_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ break;
+
+ default:
+ assert(!"Unhandled architecture in ProcessMacOSX::GetSoftwareBreakpointTrapOpcode()");
+ return 0;
+ }
+
+ if (trap_opcode && trap_opcode_size)
+ {
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ }
+ return 0;
+}
+uint32_t
+ProcessMacOSX::UpdateThreadListIfNeeded ()
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ProcessMacOSX::%s (pid = %4.4x)", __FUNCTION__, GetID());
+
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID())
+ {
+ // Update the thread list's stop id immediately so we don't recurse into this function.
+ thread_array_t thread_list = NULL;
+ mach_msg_type_number_t thread_list_count = 0;
+ task_t task = Task().GetTaskPort();
+ Error err(::task_threads (task, &thread_list, &thread_list_count), eErrorTypeMachKernel);
+
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count);
+
+ if (err.GetError() == KERN_SUCCESS && thread_list_count > 0)
+ {
+ ThreadList curr_thread_list (this);
+ curr_thread_list.SetStopID(stop_id);
+
+ size_t idx;
+ // Iterator through the current thread list and see which threads
+ // we already have in our list (keep them), which ones we don't
+ // (add them), and which ones are not around anymore (remove them).
+ for (idx = 0; idx < thread_list_count; ++idx)
+ {
+ const lldb::tid_t tid = thread_list[idx];
+ ThreadSP thread_sp(GetThreadList().FindThreadByID (tid, false));
+ if (thread_sp.get() == NULL)
+ thread_sp.reset (new ThreadMacOSX (*this, tid));
+ curr_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list = curr_thread_list;
+
+ // Free the vm memory given to us by ::task_threads()
+ vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (lldb::tid_t));
+ ::vm_deallocate (::mach_task_self(),
+ (vm_address_t)thread_list,
+ thread_list_size);
+ }
+ }
+ return GetThreadList().GetSize(false);
+}
+
+
+void
+ProcessMacOSX::RefreshStateAfterStop ()
+{
+ // If we are attaching, let our dynamic loader plug-in know so it can get
+ // an initial list of shared libraries.
+
+ // We must be attaching if we don't already have a valid architecture
+ if (!m_arch_spec.IsValid())
+ {
+ Module *exe_module = GetTarget().GetExecutableModule().get();
+ if (exe_module)
+ m_arch_spec = exe_module->GetArchitecture();
+ }
+ // Discover new threads:
+ UpdateThreadListIfNeeded ();
+
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+
+ // Let each thread know of any exceptions
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ task_t task = Task().GetTaskPort();
+ size_t i;
+ for (i=0; i<m_exception_messages.size(); ++i)
+ {
+ // Let the thread list figure use the ProcessMacOSX to forward all exceptions
+ // on down to each thread.
+ if (m_exception_messages[i].state.task_port == task)
+ {
+ ThreadSP thread_sp(m_thread_list.FindThreadByID(m_exception_messages[i].state.thread_port));
+ if (thread_sp.get())
+ {
+ ThreadMacOSX *macosx_thread = (ThreadMacOSX *)thread_sp.get();
+ macosx_thread->NotifyException (m_exception_messages[i].state);
+ }
+ }
+ if (log)
+ m_exception_messages[i].PutToLog(log);
+ }
+
+}
+
+Error
+ProcessMacOSX::DoHalt ()
+{
+ return Signal (SIGSTOP);
+}
+
+Error
+ProcessMacOSX::WillDetach ()
+{
+ Error error;
+ const StateType state = m_private_state.GetValue();
+
+ if (IsRunning(state))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process must be stopped in order to detach.");
+ }
+ return error;
+}
+
+Error
+ProcessMacOSX::DoSIGSTOP (bool clear_all_breakpoints)
+{
+ Error error;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("ProcessMacOSX::DoSIGSTOP()");
+ EventSP event_sp;
+ TimeValue timeout_time;
+
+ StateType state = m_private_state.GetValue();
+
+ lldb::pid_t pid = GetID();
+
+ if (IsRunning(state))
+ {
+ // If our process is running, we need to SIGSTOP it so we can detach.
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() - kill (%i, SIGSTOP)", pid);
+
+ // Send the SIGSTOP and wait a few seconds for it to stop
+
+ // Pause the Private State Thread so it doesn't intercept the events we need to wait for.
+ PausePrivateStateThread();
+
+ m_thread_list.DiscardThreadPlans();
+
+ // First jettison all the current thread plans, since we want to make sure it
+ // really just stops.
+
+ if (::kill (pid, SIGSTOP) == 0)
+ error.Clear();
+ else
+ error.SetErrorToErrno();
+
+ if (error.Fail())
+ error.PutToLog(log, "::kill (pid = %i, SIGSTOP)", pid);
+
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+
+ state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
+
+ // Resume the private state thread at this point.
+ ResumePrivateStateThread();
+
+ if (!StateIsStoppedState (state))
+ {
+ if (log)
+ log->Printf("ProcessMacOSX::DoSIGSTOP() failed to stop after sending SIGSTOP");
+ return error;
+ }
+ if (clear_all_breakpoints)
+ GetTarget().DisableAllBreakpoints();
+ }
+ else if (!HasExited(state))
+ {
+ if (clear_all_breakpoints)
+ GetTarget().DisableAllBreakpoints();
+
+// const uint32_t num_threads = GetNumThreads();
+// for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx)
+// {
+// Thread *thread = GetThreadAtIndex(thread_idx);
+// thread->SetResumeState(eStateRunning);
+// if (thread_idx == 0)
+// thread->SetResumeSignal(SIGSTOP);
+// }
+
+ // Our process was stopped, so resume it and then SIGSTOP it so we can
+ // detach.
+ // But discard all the thread plans first, so we don't keep going because we
+ // are in mid-plan.
+
+ // Pause the Private State Thread so it doesn't intercept the events we need to wait for.
+ PausePrivateStateThread();
+
+ m_thread_list.DiscardThreadPlans();
+
+ if (::kill (pid, SIGSTOP) == 0)
+ error.Clear();
+ else
+ error.SetErrorToErrno();
+
+ if (log || error.Fail())
+ error.PutToLog(log, "ProcessMacOSX::DoSIGSTOP() ::kill (pid = %i, SIGSTOP)", pid);
+
+ error = PrivateResume(LLDB_INVALID_THREAD_ID);
+
+ // Wait a few seconds for our process to resume
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+ state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
+
+ // Make sure the process resumed
+ if (StateIsStoppedState (state))
+ {
+ if (log)
+ log->Printf ("ProcessMacOSX::DoSIGSTOP() couldn't resume process, state = %s", StateAsCString(state));
+ error.SetErrorStringWithFormat("ProcessMacOSX::DoSIGSTOP() couldn't resume process, state = %s", StateAsCString(state));
+ }
+ else
+ {
+ // Send the SIGSTOP and wait a few seconds for it to stop
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+ state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
+ if (!StateIsStoppedState (state))
+ {
+ if (log)
+ log->Printf("ProcessMacOSX::DoSIGSTOP() failed to stop after sending SIGSTOP");
+ error.SetErrorString("ProcessMacOSX::DoSIGSTOP() failed to stop after sending SIGSTOP");
+ }
+ }
+ // Resume the private state thread at this point.
+ ResumePrivateStateThread();
+ }
+
+ return error;
+}
+
+Error
+ProcessMacOSX::DoDestroy ()
+{
+ Error error;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy()");
+
+ error = DoSIGSTOP (true);
+ if (error.Success())
+ {
+ StopSTDIOThread(true);
+
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() DoSIGSTOP succeeded");
+ const StateType state = m_private_state.GetValue();
+ // Scope for "locker" so we can reply to all of our exceptions (the SIGSTOP
+ // exception).
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ReplyToAllExceptions();
+ }
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() replied to all exceptions");
+
+ // Shut down the exception thread and cleanup our exception remappings
+ Task().ShutDownExceptionThread();
+
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() exception thread has been shutdown");
+
+ if (!HasExited(state))
+ {
+ lldb::pid_t pid = GetID();
+
+ // Detach from our process while we are stopped.
+ errno = 0;
+
+ // Detach from our process
+ ::ptrace (PT_KILL, pid, 0, 0);
+
+ error.SetErrorToErrno();
+
+ if (log || error.Fail())
+ error.PutToLog (log, "::ptrace (PT_KILL, %u, 0, 0)", pid);
+
+ // Resume our task and let the SIGKILL do its thing. The thread named
+ // "ProcessMacOSX::WaitForChildProcessToExit(void*)" will catch the
+ // process exiting, so we don't need to set our state to exited in this
+ // function.
+ Task().Resume();
+ }
+
+ // NULL our task out as we have already retored all exception ports
+ Task().Clear();
+
+ // Clear out any notion of the process we once were
+ Clear();
+ }
+ return error;
+}
+
+ByteOrder
+ProcessMacOSX::GetByteOrder () const
+{
+ return m_byte_order;
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessMacOSX::IsAlive ()
+{
+ return MachTask::IsValid (Task().GetTaskPort());
+}
+
+lldb::addr_t
+ProcessMacOSX::GetImageInfoAddress()
+{
+ return Task().GetDYLDAllImageInfosAddress();
+}
+
+DynamicLoader *
+ProcessMacOSX::GetDynamicLoader()
+{
+ return m_dynamic_loader_ap.get();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSX::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error& error)
+{
+ return Task().ReadMemory(addr, buf, size, error);
+}
+
+size_t
+ProcessMacOSX::DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error& error)
+{
+ return Task().WriteMemory(addr, buf, size, error);
+}
+
+lldb::addr_t
+ProcessMacOSX::DoAllocateMemory (size_t size, uint32_t permissions, Error& error)
+{
+ return Task().AllocateMemory (size, permissions, error);
+}
+
+Error
+ProcessMacOSX::DoDeallocateMemory (lldb::addr_t ptr)
+{
+ return Task().DeallocateMemory (ptr);
+}
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSX::GetSTDOUT (char *buf, size_t buf_size, Error &error)
+{
+ error.Clear();
+ Mutex::Locker locker(m_stdio_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.data(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.data(), bytes_available);
+ m_stdout_data.clear();
+
+ //ResetEventBits(eBroadcastBitSTDOUT);
+ }
+ }
+ return bytes_available;
+}
+
+size_t
+ProcessMacOSX::GetSTDERR (char *buf, size_t buf_size, Error &error)
+{
+ error.Clear();
+ return 0;
+}
+
+size_t
+ProcessMacOSX::PutSTDIN (const char *buf, size_t buf_size, Error &error)
+{
+ if (m_child_stdin == -1)
+ {
+ error.SetErrorString ("Invalid child stdin handle.");
+ }
+ else
+ {
+ ssize_t bytes_written = ::write (m_child_stdin, buf, buf_size);
+ if (bytes_written == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return bytes_written;
+ }
+ }
+ return 0;
+}
+
+Error
+ProcessMacOSX::EnableBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ const lldb::addr_t addr = bp_site->GetLoadAddress();
+ const lldb::user_id_t site_id = bp_site->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSX::EnableBreakpoint (site_id = %d) addr = 0x%8.8llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessMacOSX::EnableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (bp_site->HardwarePreferred())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp_site->GetThreadID()).get();
+ if (thread)
+ {
+ bp_site->SetHardwareIndex (thread->SetHardwareBreakpoint(bp_site));
+ if (bp_site->IsHardware())
+ {
+ bp_site->SetEnabled(true);
+ return error;
+ }
+ }
+ }
+
+ // Just let lldb::Process::EnableSoftwareBreakpoint() handle everything...
+ return EnableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessMacOSX::DisableBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ const lldb::addr_t addr = bp_site->GetLoadAddress();
+ const lldb::user_id_t site_id = bp_site->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp_site->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->ClearHardwareBreakpoint(bp_site))
+ {
+ bp_site->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSX::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS (hardware)", site_id, (uint64_t)addr);
+ return error;
+ }
+ }
+ error.SetErrorString("hardware breakpoints are no supported");
+ return error;
+ }
+
+ // Just let lldb::Process::EnableSoftwareBreakpoint() handle everything...
+ return DisableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessMacOSX::EnableWatchpoint (WatchpointLocation *wp)
+{
+ Error error;
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+ lldb::addr_t addr = wp->GetLoadAddress();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSX::EnableWatchpoint(watchID = %d)", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessMacOSX::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
+ return error;
+ }
+ else
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ wp->SetHardwareIndex (thread->SetHardwareWatchpoint (wp));
+ if (wp->IsHardware ())
+ {
+ wp->SetEnabled(true);
+ return error;
+ }
+ }
+ else
+ {
+ error.SetErrorString("Watchpoints currently only support thread specific watchpoints.");
+ }
+ }
+ }
+ return error;
+}
+
+Error
+ProcessMacOSX::DisableWatchpoint (WatchpointLocation *wp)
+{
+ Error error;
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+
+ lldb::addr_t addr = wp->GetLoadAddress();
+ if (log)
+ log->Printf ("ProcessMacOSX::DisableWatchpoint (watchID = %d) addr = 0x%8.8llx", watchID, (uint64_t)addr);
+
+ if (wp->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->ClearHardwareWatchpoint (wp))
+ {
+ wp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSX::Disablewatchpoint (watchID = %d) addr = 0x%8.8llx (hardware) => success", watchID, (uint64_t)addr);
+ return error;
+ }
+ }
+ }
+ // TODO: clear software watchpoints if we implement them
+ error.SetErrorToGenericError();
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint location argument was NULL.");
+ }
+ return error;
+}
+
+
+static ProcessMacOSX::CreateArchCalback
+ArchCallbackMap(const ArchSpec& arch_spec, ProcessMacOSX::CreateArchCalback callback, bool add )
+{
+ // We must wrap the "g_arch_map" file static in a function to avoid
+ // any global constructors so we don't get a build verification error
+ typedef std::multimap<ArchSpec, ProcessMacOSX::CreateArchCalback> ArchToProtocolMap;
+ static ArchToProtocolMap g_arch_map;
+
+ if (add)
+ {
+ g_arch_map.insert(std::make_pair(arch_spec, callback));
+ return callback;
+ }
+ else
+ {
+ ArchToProtocolMap::const_iterator pos = g_arch_map.find(arch_spec);
+ if (pos != g_arch_map.end())
+ {
+ return pos->second;
+ }
+ }
+ return NULL;
+}
+
+void
+ProcessMacOSX::AddArchCreateCallback(const ArchSpec& arch_spec, CreateArchCalback callback)
+{
+ ArchCallbackMap (arch_spec, callback, true);
+}
+
+ProcessMacOSX::CreateArchCalback
+ProcessMacOSX::GetArchCreateCallback()
+{
+ return ArchCallbackMap (m_arch_spec, NULL, false);
+}
+
+void
+ProcessMacOSX::Clear()
+{
+ // Clear any cached thread list while the pid and task are still valid
+
+ Task().Clear();
+ // Now clear out all member variables
+ CloseChildFileDescriptors();
+
+ m_flags = eFlagsNone;
+ m_thread_list.Clear();
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ m_exception_messages.clear();
+ }
+
+}
+
+bool
+ProcessMacOSX::StartSTDIOThread()
+{
+ // If we created and own the child STDIO file handles, then we track the
+ // STDIO ourselves, else we let whomever owns these file handles track
+ // the IO themselves.
+ if (m_stdio_ours)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s ( )", __FUNCTION__);
+ // Create the thread that watches for the child STDIO
+ m_stdio_thread = Host::ThreadCreate ("<lldb.process.process-macosx.stdio>", ProcessMacOSX::STDIOThread, this, NULL);
+ return m_stdio_thread != LLDB_INVALID_HOST_THREAD;
+ }
+ return false;
+}
+
+
+void
+ProcessMacOSX::StopSTDIOThread(bool close_child_fds)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s ( )", __FUNCTION__);
+ // Stop the stdio thread
+ if (m_stdio_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ Host::ThreadCancel (m_stdio_thread, NULL);
+ thread_result_t result = NULL;
+ Host::ThreadJoin (m_stdio_thread, &result, NULL);
+ if (close_child_fds)
+ CloseChildFileDescriptors();
+ else
+ {
+ // We may have given up control of these file handles, so just
+ // set them to invalid values so the STDIO thread can exit when
+ // we interrupt it with pthread_cancel...
+ m_child_stdin = -1;
+ m_child_stdout = -1;
+ m_child_stderr = -1;
+ }
+ }
+}
+
+
+void *
+ProcessMacOSX::STDIOThread(void *arg)
+{
+ ProcessMacOSX *proc = (ProcessMacOSX*) arg;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::%s (arg = %p) thread starting...", __FUNCTION__, arg);
+
+ // We start use a base and more options so we can control if we
+ // are currently using a timeout on the mach_msg. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main thread loop
+ // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ Error err;
+ int stdout_fd = proc->GetStdoutFileDescriptor();
+ int stderr_fd = proc->GetStderrFileDescriptor();
+ if (stdout_fd == stderr_fd)
+ stderr_fd = -1;
+
+ while (stdout_fd >= 0 || stderr_fd >= 0)
+ {
+ //::pthread_testcancel ();
+
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ if (stdout_fd >= 0)
+ FD_SET (stdout_fd, &read_fds);
+ if (stderr_fd >= 0)
+ FD_SET (stderr_fd, &read_fds);
+ int nfds = std::max<int>(stdout_fd, stderr_fd) + 1;
+
+ int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL);
+ if (log)
+ log->Printf("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+
+ if (num_set_fds < 0)
+ {
+ int select_errno = errno;
+ if (log)
+ {
+ err.SetError (select_errno, eErrorTypePOSIX);
+ err.LogIfError(log, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+ }
+
+ switch (select_errno)
+ {
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO
+ break;
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return NULL;
+ break;
+ case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred.
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ break;
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ }
+ else
+ {
+ char s[1024];
+ s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination
+ int bytes_read = 0;
+ if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stdout_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d (reached EOF for child STDOUT)", bytes_read);
+ stdout_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+
+ if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stderr_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d (reached EOF for child STDERR)", bytes_read);
+ stderr_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+ }
+ }
+
+ if (log)
+ log->Printf("ProcessMacOSX::%s (%p): thread exiting...", __FUNCTION__, arg);
+
+ return NULL;
+}
+
+Error
+ProcessMacOSX::DoSignal (int signal)
+{
+ Error error;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DoSignal (signal = %d)", signal);
+ if (::kill (GetID(), signal) != 0)
+ {
+ error.SetErrorToErrno();
+ error.LogIfError(log, "ProcessMacOSX::DoSignal (%d)", signal);
+ }
+ return error;
+}
+
+
+Error
+ProcessMacOSX::DoDetach()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDetach()");
+
+ Error error (DoSIGSTOP (true));
+ if (error.Success())
+ {
+ CloseChildFileDescriptors ();
+
+ // Scope for "locker" so we can reply to all of our exceptions (the SIGSTOP
+ // exception).
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ReplyToAllExceptions();
+ }
+
+ // Shut down the exception thread and cleanup our exception remappings
+ Task().ShutDownExceptionThread();
+
+ lldb::pid_t pid = GetID();
+
+ // Detach from our process while we are stopped.
+ errno = 0;
+
+ // Detach from our process
+ ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
+
+ error.SetErrorToErrno();
+
+ if (log || error.Fail())
+ error.PutToLog(log, "::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
+
+ // Resume our task
+ Task().Resume();
+
+ // NULL our task out as we have already retored all exception ports
+ Task().Clear();
+
+ // Clear out any notion of the process we once were
+ Clear();
+
+ SetPrivateState (eStateDetached);
+ }
+ return error;
+}
+
+
+
+Error
+ProcessMacOSX::ReplyToAllExceptions()
+{
+ Error error;
+ Mutex::Locker locker(m_exception_messages_mutex);
+ if (m_exception_messages.empty() == false)
+ {
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+
+ MachException::Message::iterator pos;
+ MachException::Message::iterator begin = m_exception_messages.begin();
+ MachException::Message::iterator end = m_exception_messages.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ int resume_signal = -1;
+ ThreadSP thread_sp = m_thread_list.FindThreadByID(pos->state.thread_port);
+ if (thread_sp.get())
+ resume_signal = thread_sp->GetResumeSignal();
+ if (log)
+ log->Printf ("Replying to exception %d for thread 0x%4.4x (resume_signal = %i).", std::distance(begin, pos), thread_sp->GetID(), resume_signal);
+ Error curr_error (pos->Reply (Task().GetTaskPort(), GetID(), resume_signal));
+
+ // Only report the first error
+ if (curr_error.Fail() && error.Success())
+ error = curr_error;
+
+ error.LogIfError(log, "Error replying to exception");
+ }
+
+ // Erase all exception message as we should have used and replied
+ // to them all already.
+ m_exception_messages.clear();
+ }
+ return error;
+}
+
+
+Error
+ProcessMacOSX::PrivateResume (lldb::tid_t tid)
+{
+
+ Mutex::Locker locker(m_exception_messages_mutex);
+ Error error (ReplyToAllExceptions());
+
+ // Let the thread prepare to resume and see if any threads want us to
+ // step over a breakpoint instruction (ProcessWillResume will modify
+ // the value of stepOverBreakInstruction).
+ //StateType process_state = m_thread_list.ProcessWillResume(this);
+
+ // Set our state accordingly
+ SetPrivateState (eStateRunning);
+
+ // Now resume our task.
+ error = Task().Resume();
+ return error;
+}
+
+// Called by the exception thread when an exception has been received from
+// our process. The exception message is completely filled and the exception
+// data has already been copied.
+void
+ProcessMacOSX::ExceptionMessageReceived (const MachException::Message& exceptionMessage)
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+
+ if (m_exception_messages.empty())
+ Task().Suspend();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "ProcessMacOSX::ExceptionMessageReceived ( )");
+
+ // Use a locker to automatically unlock our mutex in case of exceptions
+ // Add the exception to our internal exception stack
+ m_exception_messages.push_back(exceptionMessage);
+}
+
+
+//bool
+//ProcessMacOSX::GetProcessInfo (struct kinfo_proc* proc_info)
+//{
+// int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, GetID() };
+// size_t buf_size = sizeof(struct kinfo_proc);
+//
+// if (::sysctl (mib, (unsigned)(sizeof(mib)/sizeof(int)), &proc_info, &buf_size, NULL, 0) == 0)
+// return buf_size > 0;
+//
+// return false;
+//}
+//
+//
+void
+ProcessMacOSX::ExceptionMessageBundleComplete()
+{
+ // We have a complete bundle of exceptions for our child process.
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s: %d exception messages.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ if (!m_exception_messages.empty())
+ {
+ SetPrivateState (eStateStopped);
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s empty exception messages bundle.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ }
+}
+
+bool
+ProcessMacOSX::ReleaseChildFileDescriptors ( int *stdin_fileno, int *stdout_fileno, int *stderr_fileno )
+{
+ if (stdin_fileno)
+ *stdin_fileno = m_child_stdin;
+ if (stdout_fileno)
+ *stdout_fileno = m_child_stdout;
+ if (stderr_fileno)
+ *stderr_fileno = m_child_stderr;
+ // Stop the stdio thread if we have one, but don't have it close the child
+ // file descriptors since we are giving control of these descriptors to the
+ // caller
+ bool close_child_fds = false;
+ StopSTDIOThread(close_child_fds);
+ return true;
+}
+
+void
+ProcessMacOSX::AppendSTDOUT (const char* s, size_t len)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s (<%d> %s) ...", __FUNCTION__, len, s);
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.append(s, len);
+
+ // FIXME: Make a real data object for this and put it out.
+ BroadcastEventIfUnique (eBroadcastBitSTDOUT);
+}
+
+lldb::pid_t
+ProcessMacOSX::LaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ PDLaunchType launch_type,
+ Error &launch_err)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ m_arch_spec = arch_spec;
+
+ if (launch_type == eLaunchDefault)
+ launch_type = eLaunchPosixSpawn;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s( path = '%s', argv = %p, envp = %p, launch_type = %u )", __FUNCTION__, path, argv, envp, launch_type);
+
+ // Fork a child process for debugging
+ SetPrivateState (eStateLaunching);
+ switch (launch_type)
+ {
+ case eLaunchForkExec:
+ SetID(ProcessMacOSX::ForkChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+ case eLaunchPosixSpawn:
+ SetID(ProcessMacOSX::PosixSpawnChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+#if defined (__arm__)
+
+ case eLaunchSpringBoard:
+ {
+ const char *app_ext = strstr(path, ".app");
+ if (app_ext != NULL)
+ {
+ std::string app_bundle_path(path, app_ext + strlen(".app"));
+ return SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, launch_err);
+ }
+ }
+ break;
+
+#endif
+
+ default:
+ // Invalid launch
+ launch_err.SetErrorToGenericError ();
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+ lldb::pid_t pid = GetID();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we don't have a valid process ID and no one has set the error,
+ // then return a generic error
+ if (launch_err.Success())
+ launch_err.SetErrorToGenericError ();
+ }
+ else
+ {
+ // Make sure we can get our task port before going any further
+ Task().GetTaskPortForProcessID (launch_err);
+
+ // If that goes well then kick off our exception thread
+ if (launch_err.Success())
+ Task().StartExceptionThread(launch_err);
+
+ if (launch_err.Success())
+ {
+ //m_path = path;
+// size_t i;
+// if (argv)
+// {
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+// }
+
+ StartSTDIOThread();
+
+ if (launch_type == eLaunchPosixSpawn)
+ {
+
+ //SetState (eStateAttaching);
+ errno = 0;
+ if (::ptrace (PT_ATTACHEXC, pid, 0, 0) == 0)
+ launch_err.Clear();
+ else
+ launch_err.SetErrorToErrno();
+
+ if (launch_err.Fail() || log)
+ launch_err.PutToLog(log, "::ptrace (PT_ATTACHEXC, pid = %i, 0, 0 )", pid);
+
+ if (launch_err.Success())
+ m_flags.Set (eFlagsAttached);
+ else
+ SetPrivateState (eStateExited);
+ }
+ else
+ {
+ launch_err.Clear();
+ }
+ }
+ else
+ {
+ // We were able to launch the process, but not get its task port
+ // so now we need to make it sleep with da fishes.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ ::ptrace (PT_KILL, pid, 0, 0 );
+ ::kill (pid, SIGCONT);
+ pid = LLDB_INVALID_PROCESS_ID;
+ }
+
+ }
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSX::PosixSpawnChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ Error &err
+)
+{
+ posix_spawnattr_t attr;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+
+ Error local_err; // Errors that don't affect the spawning.
+ if (log)
+ log->Printf ("%s ( path='%s', argv=%p, envp=%p, process )", __FUNCTION__, path, argv, envp);
+ err.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnattr_init ( &attr )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+ err.SetError( ::posix_spawnattr_setflags (&attr, POSIX_SPAWN_START_SUSPENDED), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+#if !defined(__arm__)
+
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ cpu_type_t cpu = arch_spec.GetCPUType();
+ if (cpu != 0 && cpu != CPU_TYPE_ANY && cpu != LLDB_INVALID_CPUTYPE)
+ {
+ size_t ocount = 0;
+ err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu, ocount);
+
+ if (err.Fail() != 0 || ocount != 1)
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+#endif
+
+ lldb_utility::PseudoTerminal pty;
+
+ posix_spawn_file_actions_t file_actions;
+ err.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+ int file_actions_valid = err.Success();
+ if (!file_actions_valid || log)
+ err.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )");
+ Error stdio_err;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (file_actions_valid)
+ {
+ // If the user specified any STDIO files, then use those
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stderr_path != NULL && stderr_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, stderr_path, O_RDWR, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR, mode = 0 )", stderr_path);
+ }
+
+ if (stdin_path != NULL && stdin_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, stdin_path, O_RDONLY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY, mode = 0 )", stdin_path);
+ }
+
+ if (stdout_path != NULL && stdout_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, stdout_path, O_WRONLY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY, mode = 0 )", stdout_path);
+ }
+ }
+ else
+ {
+ // The user did not specify any STDIO files, use a pseudo terminal.
+ // Callers can then access the file handles using the
+ // ProcessMacOSX::ReleaseChildFileDescriptors() function, otherwise
+ // this class will spawn a thread that tracks STDIO and buffers it.
+ process->SetSTDIOIsOurs(true);
+ char error_str[1024];
+ if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)))
+ {
+ const char* slave_name = pty.GetSlaveName(error_str, sizeof(error_str));
+ if (slave_name == NULL)
+ slave_name = "/dev/null";
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, slave_name, O_RDWR|O_NOCTTY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR|O_NOCTTY, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, slave_name, O_RDONLY|O_NOCTTY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY|O_NOCTTY, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, slave_name, O_WRONLY|O_NOCTTY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY|O_NOCTTY, mode = 0 )", slave_name);
+ }
+ else
+ {
+ if (error_str[0])
+ stdio_err.SetErrorString(error_str);
+ else
+ stdio_err.SetErrorString("Unable to open master side of pty for inferior.");
+ }
+
+ }
+ err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp);
+
+ if (stdio_err.Success())
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ else
+ {
+ err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp);
+ }
+
+ // We have seen some cases where posix_spawnp was returning a valid
+ // looking pid even when an error was returned, so clear it out
+ if (err.Fail())
+ pid = LLDB_INVALID_PROCESS_ID;
+
+ if (file_actions_valid)
+ {
+ local_err.SetError( ::posix_spawn_file_actions_destroy (&file_actions), eErrorTypePOSIX);
+ if (local_err.Fail() || log)
+ local_err.PutToLog(log, "::posix_spawn_file_actions_destroy ( &file_actions )");
+ }
+
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSX::ForkChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ Error &launch_err
+)
+{
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ assert(!"TODO: ForkChildForPTraceDebugging doesn't currently support fork/exec with user file handles...");
+ }
+ else
+ {
+
+ // Use a fork that ties the child process's stdin/out/err to a pseudo
+ // terminal so we can read it in our ProcessMacOSX::STDIOThread
+ // as unbuffered io.
+ lldb_utility::PseudoTerminal pty;
+ char error_str[1024];
+ pid = pty.Fork(error_str, sizeof(error_str));
+
+ if (pid < 0)
+ {
+ launch_err.SetErrorString (error_str);
+ //--------------------------------------------------------------
+ // Error during fork.
+ //--------------------------------------------------------------
+ return pid;
+ }
+ else if (pid == 0)
+ {
+ //--------------------------------------------------------------
+ // Child process
+ //--------------------------------------------------------------
+ ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process
+ ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions
+
+ // If our parent is setgid, lets make sure we don't inherit those
+ // extra powers due to nepotism.
+ ::setgid (getgid ());
+
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (0, 0); // Set the child process group to match its pid
+
+ // Sleep a bit to before the exec call
+ ::sleep (1);
+
+ // Turn this process into
+ ::execv (path, (char * const *)argv);
+ // Exit with error code. Child process should have taken
+ // over in above exec call and if the exec fails it will
+ // exit the child process below.
+ ::exit (127);
+ }
+ else
+ {
+ //--------------------------------------------------------------
+ // Parent process
+ //--------------------------------------------------------------
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (pid, pid); // Set the child process group to match its pid
+
+ if (process != NULL)
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ return pid;
+}
+
+#if defined (__arm__)
+
+lldb::pid_t
+ProcessMacOSX::SBLaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ Error &launch_err
+)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+ m_pid = ProcessMacOSX::SBLaunchForDebug(path, argv, envp, this, launch_err);
+ if (m_pid != 0)
+ {
+ m_flags |= eFlagsUsingSBS;
+ //m_path = path;
+// size_t i;
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+ Task().StartExceptionThread();
+ StartSTDIOThread();
+ SetState (eStateAttaching);
+ int err = ptrace (PT_ATTACHEXC, m_pid, 0, 0);
+ if (err == 0)
+ {
+ m_flags |= eFlagsAttached;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "successfully attached to pid %d", m_pid);
+ }
+ else
+ {
+ SetState (eStateExited);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "error: failed to attach to pid %d", m_pid);
+ }
+ }
+ return m_pid;
+}
+
+#include <servers/bootstrap.h>
+#include "CFBundle.h"
+#include "CFData.h"
+#include "CFString.h"
+
+lldb::pid_t
+ProcessMacOSX::SBLaunchForDebug
+(
+ const char *app_bundle_path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ Error &launch_err
+)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process);
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ if (argv[0] == NULL)
+ return LLDB_INVALID_PROCESS_ID;
+
+ size_t argc = 0;
+ // Count the number of arguments
+ while (argv[argc] != NULL)
+ argc++;
+
+ // Enumerate the arguments
+ size_t first_launch_arg_idx = 1;
+ CFReleaser<CFMutableArrayRef> launch_argv;
+
+ if (argv[first_launch_arg_idx])
+ {
+ size_t launch_argc = argc > 0 ? argc - 1 : 0;
+ launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks));
+ size_t i;
+ char const *arg;
+ CFString launch_arg;
+ for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++)
+ {
+ launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8));
+ if (launch_arg.get() != NULL)
+ CFArrayAppendValue(launch_argv.get(), launch_arg.get());
+ else
+ break;
+ }
+ }
+
+ // Next fill in the arguments dictionary. Note, the envp array is of the form
+ // Variable=value but SpringBoard wants a CF dictionary. So we have to convert
+ // this here.
+
+ CFReleaser<CFMutableDictionaryRef> launch_envp;
+
+ if (envp[0])
+ {
+ launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ const char *value;
+ int name_len;
+ CFString name_string, value_string;
+
+ for (int i = 0; envp[i] != NULL; i++)
+ {
+ value = strstr (envp[i], "=");
+
+ // If the name field is empty or there's no =, skip it. Somebody's messing with us.
+ if (value == NULL || value == envp[i])
+ continue;
+
+ name_len = value - envp[i];
+
+ // Now move value over the "="
+ value++;
+
+ name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false));
+ value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8));
+ CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get());
+ }
+ }
+
+ CFString stdout_cf_path;
+ CFString stderr_cf_path;
+ PseudoTerminal pty;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stdout_path)
+ stdout_cf_path.SetFileSystemRepresentation (stdout_path);
+ if (stderr_path)
+ stderr_cf_path.SetFileSystemRepresentation (stderr_path);
+ }
+ else
+ {
+ process->SetSTDIOIsOurs(true);
+ PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
+ if (pty_err == PseudoTerminal::success)
+ {
+ const char* slave_name = pty.SlaveName();
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name);
+ if (slave_name && slave_name[0])
+ {
+ ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO);
+ stdout_cf_path.SetFileSystemRepresentation (slave_name);
+ stderr_cf_path.(stdout_cf_path);
+ }
+ }
+ }
+
+ if (stdout_cf_path.get() == NULL)
+ stdout_cf_path.SetFileSystemRepresentation ("/dev/null");
+ if (stderr_cf_path.get() == NULL)
+ stderr_cf_path.SetFileSystemRepresentation ("/dev/null");
+
+ CFBundle bundle(app_bundle_path);
+ CFStringRef bundleIDCFStr = bundle.GetIdentifier();
+ std::string bundleID;
+ if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
+ {
+ struct stat app_bundle_stat;
+ if (::stat (app_bundle_path, &app_bundle_stat) < 0)
+ {
+ launch_err.SetError(errno, eErrorTypePOSIX);
+ launch_err.SetErrorStringWithFormat("%s: \"%s\".\n", launch_err.AsString(), app_bundle_path);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: %s", __FUNCTION__, launch_err.AsCString());
+ }
+ else
+ {
+ launch_err.SetError(-1, eErrorTypeGeneric);
+ launch_err.SetErrorStringWithFormat("Failed to extract CFBundleIdentifier from %s.\n", app_bundle_path);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
+
+
+ CFData argv_data(NULL);
+
+ if (launch_argv.get())
+ {
+ if (argv_data.Serialize(launch_argv.get(), kCFPropertyListBinaryFormat_v1_0) == NULL)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: failed to serialize launch arg array...", __FUNCTION__);
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__);
+
+ // Find SpringBoard
+ SBSApplicationLaunchError sbs_error = 0;
+ sbs_error = SBSLaunchApplication ( bundleIDCFStr,
+ (CFURLRef)NULL, // openURL
+ launch_argv.get(),
+ launch_envp.get(), // CFDictionaryRef environment
+ stdout_cf_path.get(),
+ stderr_cf_path.get(),
+ SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice);
+
+
+ launch_err.SetError(sbs_error, eErrorTypeSpringBoard);
+
+ if (sbs_error == SBSApplicationLaunchErrorSuccess)
+ {
+ static const useconds_t pid_poll_interval = 200000;
+ static const useconds_t pid_poll_timeout = 30000000;
+
+ useconds_t pid_poll_total = 0;
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired
+ // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started
+ // yet, or that it died very quickly (if you weren't using waitForDebugger).
+ while (!pid_found && pid_poll_total < pid_poll_timeout)
+ {
+ usleep (pid_poll_interval);
+ pid_poll_total += pid_poll_interval;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str());
+ pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ }
+
+ if (pid_found)
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFD();
+ process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid);
+ }
+ else
+ {
+ LogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str());
+ }
+ return pid;
+ }
+
+ LogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error);
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+#endif // #if defined (__arm__)
+
+
+#include "MachThreadContext_x86_64.h"
+#include "MachThreadContext_i386.h"
+#include "MachThreadContext_arm.h"
+
+void
+ProcessMacOSX::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+
+ MachThreadContext_x86_64::Initialize();
+ MachThreadContext_i386::Initialize();
+ MachThreadContext_arm::Initialize();
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+
+ Log::Callbacks log_callbacks = {
+ ProcessMacOSXLog::DisableLog,
+ ProcessMacOSXLog::EnableLog,
+ ProcessMacOSXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessMacOSX::GetPluginNameStatic(), log_callbacks);
+
+
+ }
+}
+
+
+
diff --git a/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h
new file mode 100644
index 0000000..8388d4e
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h
@@ -0,0 +1,490 @@
+//===-- ProcessMacOSX.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_MacOSXProcess_H_
+#define liblldb_MacOSXProcess_H_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+// Project includes
+#include "MachTask.h"
+#include "MachException.h"
+
+typedef enum PDLaunch
+{
+ eLaunchDefault = 0,
+ eLaunchPosixSpawn,
+ eLaunchForkExec,
+#if defined (__arm__)
+ eLaunchSpringBoard,
+#endif
+} PDLaunchType;
+
+
+
+class ThreadMacOSX;
+class MachThreadContext;
+
+class ProcessMacOSX :
+ public lldb_private::Process
+{
+public:
+ friend class ThreadMacOSX;
+ friend class MachTask;
+
+ typedef MachThreadContext* (*CreateArchCalback) (const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static Process*
+ CreateInstance (lldb_private::Target& target, lldb_private::Listener &listener);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessMacOSX(lldb_private::Target& target, lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessMacOSX();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb_private::Target &target);
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillLaunch (lldb_private::Module* module);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module* module,
+ char const *argv[], // Can be NULL
+ char const *envp[], // Can be NULL
+ const char *stdin_path, // Can be NULL
+ const char *stdout_path, // Can be NULL
+ const char *stderr_path); // Can be NULL
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb_private::Error
+ WillAttach (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttach (lldb::pid_t pid);
+
+ virtual void
+ DidAttach ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt ();
+
+ virtual lldb_private::Error
+ WillDetach ();
+
+ virtual lldb_private::Error
+ DoDetach ();
+
+ virtual lldb_private::Error
+ DoSignal (int signal);
+
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ virtual lldb::addr_t
+ GetImageInfoAddress();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t
+ GetSTDOUT (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ GetSTDERR (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+ static void
+ AddArchCreateCallback(const lldb_private::ArchSpec& arch_spec,
+ ProcessMacOSX::CreateArchCalback callback);
+
+protected:
+
+ bool m_stdio_ours; // True if we created and own the child STDIO file handles, false if they were supplied to us and owned by someone else
+ int m_child_stdin;
+ int m_child_stdout;
+ int m_child_stderr;
+ MachTask m_task; // The mach task for this process
+ lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
+ lldb::thread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio
+ lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio
+ std::string m_stdout_data;
+ MachException::Message::collection m_exception_messages; // A collection of exception messages caught when listening to the exception port
+ lldb_private::Mutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages
+ lldb_private::ArchSpec m_arch_spec;
+ std::auto_ptr<lldb_private::DynamicLoader> m_dynamic_loader_ap;
+// lldb::thread_t m_wait_thread;
+ lldb::ByteOrder m_byte_order;
+
+ //----------------------------------------------------------------------
+ // Child process control
+ //----------------------------------------------------------------------
+ lldb::pid_t
+ LaunchForDebug (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ PDLaunchType launch_type,
+ lldb_private::Error &launch_err);
+
+ static lldb::pid_t
+ ForkChildForPTraceDebugging (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ lldb_private::Error &launch_err);
+
+ static lldb::pid_t
+ PosixSpawnChildForPTraceDebugging (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ lldb_private::Error &launch_err);
+
+#if defined (__arm__)
+ lldb::pid_t
+ SBLaunchForDebug (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ lldb_private::Error &launch_err);
+
+ static lldb::pid_t
+ SBLaunchForDebug (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ lldb_private::Error &launch_err);
+#endif
+
+ //----------------------------------------------------------------------
+ // Exception thread functions
+ //----------------------------------------------------------------------
+ bool
+ StartSTDIOThread ();
+
+ void
+ StopSTDIOThread (bool close_child_fds);
+
+ static void *
+ STDIOThread (void *arg);
+
+ void
+ ExceptionMessageReceived (const MachException::Message& exceptionMessage);
+
+ void
+ ExceptionMessageBundleComplete ();
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ ProcessIDIsValid ( ) const;
+
+ MachTask&
+ Task() { return m_task; }
+
+ const MachTask&
+ Task() const { return m_task; }
+
+ bool
+ IsRunning ( lldb::StateType state )
+ {
+ return state == lldb::eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( lldb::StateType state)
+ {
+ return state == lldb::eStateStepping;
+ }
+ bool
+ CanResume ( lldb::StateType state)
+ {
+ return state == lldb::eStateStopped;
+ }
+
+ bool
+ HasExited (lldb::StateType state)
+ {
+ return state == lldb::eStateExited;
+ }
+
+ void
+ SetChildFileDescriptors (int stdin_fileno, int stdout_fileno, int stderr_fileno)
+ {
+ m_child_stdin = stdin_fileno;
+ m_child_stdout = stdout_fileno;
+ m_child_stderr = stderr_fileno;
+ }
+
+ int
+ GetStdinFileDescriptor () const
+ {
+ return m_child_stdin;
+ }
+
+ int
+ GetStdoutFileDescriptor () const
+ {
+ return m_child_stdout;
+ }
+ int
+ GetStderrFileDescriptor () const
+ {
+ return m_child_stderr;
+ }
+ bool
+ ReleaseChildFileDescriptors ( int *stdin_fileno, int *stdout_fileno, int *stderr_fileno );
+
+ void
+ AppendSTDOUT (const char* s, size_t len);
+
+ void
+ CloseChildFileDescriptors ()
+ {
+ if (m_child_stdin >= 0)
+ {
+ ::close (m_child_stdin);
+ m_child_stdin = -1;
+ }
+ if (m_child_stdout >= 0)
+ {
+ ::close (m_child_stdout);
+ m_child_stdout = -1;
+ }
+ if (m_child_stderr >= 0)
+ {
+ ::close (m_child_stderr);
+ m_child_stderr = -1;
+ }
+ }
+
+ bool
+ ProcessUsingSpringBoard() const
+ {
+ return m_flags.IsSet(eFlagsUsingSBS);
+ }
+
+ lldb_private::ArchSpec&
+ GetArchSpec()
+ {
+ return m_arch_spec;
+ }
+ const lldb_private::ArchSpec&
+ GetArchSpec() const
+ {
+ return m_arch_spec;
+ }
+
+ CreateArchCalback
+ GetArchCreateCallback();
+
+ enum
+ {
+ eFlagsNone = 0,
+ eFlagsAttached = (1 << 0),
+ eFlagsUsingSBS = (1 << 1)
+ };
+
+ void
+ Clear ( );
+
+ lldb_private::Error
+ ReplyToAllExceptions();
+
+ lldb_private::Error
+ PrivateResume ( lldb::tid_t tid);
+
+ lldb_private::Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ bool
+ STDIOIsOurs() const
+ {
+ return m_stdio_ours;
+ }
+
+ void
+ SetSTDIOIsOurs(bool b)
+ {
+ m_stdio_ours = b;
+ }
+
+ uint32_t
+ UpdateThreadListIfNeeded ();
+
+private:
+
+ void
+ DidLaunchOrAttach ();
+
+ lldb_private::Error
+ DoSIGSTOP (bool clear_all_breakpoints);
+
+ lldb_private::Error
+ WillLaunchOrAttach ();
+
+// static void *
+// WaitForChildProcessToExit (void *pid_ptr);
+//
+//
+ //------------------------------------------------------------------
+ // For ProcessMacOSX only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ProcessMacOSX);
+
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.cpp b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.cpp
new file mode 100644
index 0000000..4bfd1ff
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.cpp
@@ -0,0 +1,124 @@
+//===-- ProcessMacOSXLog.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMacOSXLog.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessMacOSX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+Log *
+ProcessMacOSXLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = g_log;
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+ProcessMacOSXLog::DisableLog ()
+{
+ if (g_log)
+ {
+ delete g_log;
+ g_log = NULL;
+ }
+}
+
+Log *
+ProcessMacOSXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args &args, Stream *feedback_strm)
+{
+ DisableLog ();
+ g_log = new Log (log_stream_sp);
+ if (g_log)
+ {
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ const size_t argc = args.GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *arg = args.GetArgumentAtIndex(i);
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= PD_LOG_ALL;
+ else if (::strcasestr (arg, "break") == arg ) flag_bits |= PD_LOG_BREAKPOINTS;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= PD_LOG_DEFAULT;
+ else if (::strcasestr (arg, "exc") == arg ) flag_bits |= PD_LOG_EXCEPTIONS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= PD_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= PD_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= PD_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "protections")== 0 ) flag_bits |= PD_LOG_MEMORY_PROTECTIONS;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= PD_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= PD_LOG_STEP;
+ else if (::strcasecmp (arg, "task") == 0 ) flag_bits |= PD_LOG_TASK;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= PD_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= PD_LOG_VERBOSE;
+ else if (::strcasestr (arg, "watch") == arg ) flag_bits |= PD_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = PD_LOG_DEFAULT;
+ g_log->GetMask().SetAllFlagBits(flag_bits);
+ g_log->GetOptions().SetAllFlagBits(log_options);
+ }
+ return g_log;
+}
+
+void
+ProcessMacOSXLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for '%s':\n"
+ "\tall - turn on all available logging categories\n"
+ "\tbreak - log breakpoints\n"
+ "\tdefault - enable the default set of logging categories for liblldb\n"
+ "\tmemory - log memory reads and writes\n"
+ "\tdata-short - log memory bytes for memory reads and writes for short transactions only\n"
+ "\tdata-long - log memory bytes for memory reads and writes for all transactions\n"
+ "\tprocess - log process events and activities\n"
+ "\tprotections - log memory protections\n"
+ "\ttask - log mach task calls\n"
+ "\tthread - log thread events and activities\n"
+ "\tstep - log step related activities\n"
+ "\tverbose - enable verbose loggging\n"
+ "\twatch - log watchpoint related activities\n", ProcessMacOSX::GetPluginNameStatic());
+}
+
+
+void
+ProcessMacOSXLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (mask);
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.h b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.h
new file mode 100644
index 0000000..cb2a4e8
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.h
@@ -0,0 +1,62 @@
+//===-- ProcessMacOSXLog.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_ProcessMacOSXLog_h_
+#define liblldb_ProcessMacOSXLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define PD_LOG_VERBOSE (1u << 0)
+#define PD_LOG_PROCESS (1u << 1)
+#define PD_LOG_THREAD (1u << 2)
+#define PD_LOG_EXCEPTIONS (1u << 3)
+#define PD_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define PD_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define PD_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define PD_LOG_MEMORY_PROTECTIONS (1u << 7) // Log memory protection changes
+#define PD_LOG_BREAKPOINTS (1u << 8)
+#define PD_LOG_WATCHPOINTS (1u << 9)
+#define PD_LOG_STEP (1u << 10)
+#define PD_LOG_TASK (1u << 11)
+#define PD_LOG_ALL (UINT32_MAX)
+#define PD_LOG_DEFAULT (PD_LOG_PROCESS |\
+ PD_LOG_TASK |\
+ PD_LOG_THREAD |\
+ PD_LOG_EXCEPTIONS |\
+ PD_LOG_MEMORY |\
+ PD_LOG_MEMORY_DATA_SHORT |\
+ PD_LOG_BREAKPOINTS |\
+ PD_LOG_WATCHPOINTS |\
+ PD_LOG_STEP )
+
+class ProcessMacOSXLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog ();
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, lldb_private::Args &args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_ProcessMacOSXLog_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.cpp b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.cpp
new file mode 100644
index 0000000..835d003
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.cpp
@@ -0,0 +1,1819 @@
+//===-- ProcessMacOSXRemote.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// ProcessMacOSXRemote.cpp
+// liblldb
+//
+// Created by Greg Clayton on 4/21/09.
+//
+//
+//----------------------------------------------------------------------
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+//#include <algorithm>
+//#include <map>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "ProcessMacOSXRemote.h"
+#include "ProcessMacOSXLog.h"
+#include "ThreadMacOSX.h"
+
+Process*
+ProcessMacOSXRemote::CreateInstance (Target &target)
+{
+ return new ProcessMacOSXRemote (target);
+}
+
+bool
+ProcessMacOSXRemote::CanDebug(Target &target)
+{
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target.GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessMacOSXRemote constructor
+//----------------------------------------------------------------------
+ProcessMacOSXRemote::ProcessMacOSXRemote(Target& target) :
+ Process (target),
+ m_flags (0),
+ m_arch_spec (),
+ m_dynamic_loader_ap (),
+ m_byte_order(eByteOrderInvalid)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessMacOSXRemote::~DCProcessMacOSXRemote()
+{
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+lldb::pid_t
+ProcessMacOSXRemote::DoLaunch
+(
+ Module* module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+// ::LogSetBitMask (PD_LOG_DEFAULT);
+// ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+// ::LogSetLogFile ("/dev/stdout");
+
+ ObjectFile * object_file = module->GetObjectFile();
+ if (object_file)
+ {
+ char exec_file_path[PATH_MAX];
+ FileSpec* file_spec_ptr = object_file->GetFileSpec();
+ if (file_spec_ptr)
+ file_spec_ptr->GetPath(exec_file_path, sizeof(exec_file_path));
+
+ ArchSpec arch_spec(module->GetArchitecture());
+
+ switch (arch_spec.GetCPUType())
+ {
+
+ }
+ // Set our user ID to our process ID.
+ SetID(LaunchForDebug(exec_file_path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, eLaunchDefault, GetError()));
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ GetError().SetErrorToGenericError ();
+ GetError().SetErrorStringWithFormat ("Failed to get object file from '%s' for arch %s.\n", module->GetFileSpec().GetFilename().AsCString(), module->GetArchitecture().AsCString());
+ }
+
+ // Return the process ID we have
+ return GetID();
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::DoAttach (lldb::pid_t attach_pid)
+{
+ // Set our user ID to the attached process ID (which can be invalid if
+ // the attach fails
+ lldb::pid_t pid = AttachForDebug(attach_pid);
+ SetID(pid);
+
+// if (pid != LLDB_INVALID_PROCESS_ID)
+// {
+// // Wait for a process stopped event, but don't consume it
+// if (WaitForEvents(LLDB_EVENT_STOPPED, NULL, 30))
+// {
+// }
+// }
+//
+ // Return the process ID we have
+ return pid;
+}
+
+
+void
+ProcessMacOSXRemote::DidLaunch ()
+{
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ m_dynamic_loader_ap.reset();
+ }
+ else
+ {
+ Module * exe_module = GetTarget().GetExecutableModule ().get();
+ assert(exe_module);
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ assert(exe_objfile);
+ m_byte_order = exe_objfile->GetByteOrder();
+ assert(m_byte_order != eByteOrderInvalid);
+ // Install a signal handler so we can catch when our child process
+ // dies and set the exit status correctly.
+ m_wait_thread = Host::ThreadCreate (ProcessMacOSXRemote::WaitForChildProcessToExit, &m_uid, &m_error);
+ if (m_wait_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ // Don't need to get the return value of this thread, so just let
+ // it clean up after itself when it dies.
+ Host::ThreadDetach (m_wait_thread, NULL);
+ }
+ m_dynamic_loader_ap.reset(DynamicLoader::FindPlugin(this, "macosx-dyld"));
+ }
+
+}
+
+void
+ProcessMacOSXRemote::DidAttach ()
+{
+ DidLaunch ();
+ m_need_to_run_did_attach = true;
+}
+
+bool
+ProcessMacOSXRemote::DoResume ()
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::Resume()");
+ State state = GetState();
+
+ if (CanResume(state))
+ {
+ PrivateResume(LLDB_INVALID_THREAD_ID);
+ }
+ else if (state == eStateRunning)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x is running, ignoring...", m_task.TaskPort());
+ GetError().Clear();
+
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x can't continue, ignoring...", m_task.TaskPort());
+ GetError().SetError(UINT_MAX, Error::Generic);
+ }
+
+ return GetError().Success();
+}
+
+size_t
+ProcessMacOSXRemote::GetSoftwareBreakpointTrapOpcode (BreakpointSite *bp_site)
+{
+ ModuleSP exe_module_sp(GetTarget().GetExecutableModule());
+ if (exe_module_sp.get())
+ {
+ const ArchSpec &exe_arch = exe_module_sp->GetArchitecture();
+ const uint8_t *trap_opcode = NULL;
+ uint32_t trap_opcode_size = 0;
+
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ //static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+ static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+
+ switch (exe_arch.GetCPUType())
+ {
+ case CPU_TYPE_ARM:
+ // TODO: fill this in for ARM. We need to dig up the symbol for
+ // the address in the breakpoint locaiton and figure out if it is
+ // an ARM or Thumb breakpoint.
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ trap_opcode = g_ppc_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ break;
+
+ default:
+ assert(!"Unhandled architecture in ProcessMacOSXRemote::GetSoftwareBreakpointTrapOpcode()");
+ return 0;
+ }
+
+ if (trap_opcode && trap_opcode_size)
+ {
+ if (bp_loc->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ }
+ }
+ // No executable yet, so we can't tell what the breakpoint opcode will be.
+ return 0;
+}
+uint32_t
+ProcessMacOSXRemote::UpdateThreadListIfNeeded ()
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ProcessMacOSXRemote::%s (pid = %4.4x)", __FUNCTION__, GetID());
+
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize() == 0 || stop_id != m_thread_list.GetID())
+ {
+ m_thread_list.SetID (stop_id);
+ thread_array_t thread_list = NULL;
+ mach_msg_type_number_t thread_list_count = 0;
+ task_t task = Task().TaskPort();
+ Error err(::task_threads (task, &thread_list, &thread_list_count), Error::MachKernel);
+
+ if (log || err.Fail())
+ err.Log(log, "::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count);
+
+ if (err.GetError() == KERN_SUCCESS && thread_list_count > 0)
+ {
+ ThreadList curr_thread_list;
+
+ size_t idx;
+ // Iterator through the current thread list and see which threads
+ // we already have in our list (keep them), which ones we don't
+ // (add them), and which ones are not around anymore (remove them).
+ for (idx = 0; idx < thread_list_count; ++idx)
+ {
+ const lldb::tid_t tid = thread_list[idx];
+ ThreadSP thread_sp(m_thread_list.FindThreadByID (tid));
+ if (thread_sp.get() == NULL)
+ thread_sp.reset (new ThreadMacOSX (this, tid));
+ curr_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list = curr_thread_list;
+
+ // Free the vm memory given to us by ::task_threads()
+ vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (lldb::tid_t));
+ ::vm_deallocate (::mach_task_self(),
+ (vm_address_t)thread_list,
+ thread_list_size);
+ }
+ }
+ return m_thread_list.GetSize();
+}
+
+bool
+ProcessMacOSXRemote::ShouldStop ()
+{
+ // If we are attaching, let our dynamic loader plug-in know so it can get
+ // an initial list of shared libraries.
+ if (m_need_to_run_did_attach && m_dynamic_loader_ap.get())
+ {
+ m_need_to_run_did_attach = false;
+ m_dynamic_loader_ap->DidAttach();
+ }
+
+ // We must be attaching if we don't already have a valid architecture
+ if (!m_arch_spec.IsValid())
+ {
+ Module *exe_module = GetTarget().GetExecutableModule().get();
+ if (exe_module)
+ m_arch_spec = exe_module->GetArchitecture();
+ }
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ UpdateThreadListIfNeeded ();
+
+ if (m_thread_list.ShouldStop())
+ {
+ // Let each thread know of any exceptions
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ task_t task = m_task.TaskPort();
+ size_t i;
+ for (i=0; i<m_exception_messages.size(); ++i)
+ {
+ // Let the thread list figure use the ProcessMacOSXRemote to forward all exceptions
+ // on down to each thread.
+ if (m_exception_messages[i].state.task_port == task)
+ {
+ ThreadSP thread_sp(m_thread_list.FindThreadByID(m_exception_messages[i].state.thread_port));
+ if (thread_sp.get())
+ {
+ ThreadMacOSX *macosx_thread = (ThreadMacOSX *)thread_sp.get();
+ macosx_thread->NotifyException (m_exception_messages[i].state);
+ }
+ }
+ if (log)
+ m_exception_messages[i].Log(log);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::DoHalt ()
+{
+ return Kill (SIGINT);
+}
+
+bool
+ProcessMacOSXRemote::WillDetach ()
+{
+ State state = GetState();
+
+ if (IsRunning(state))
+ {
+ m_error.SetErrorToGenericError();
+ m_error.SetErrorString("Process must be stopped in order to detach.");
+ return false;
+ }
+ return true;
+}
+
+bool
+ProcessMacOSXRemote::DoDetach ()
+{
+ m_use_public_queue = false;
+ bool success = Detach();
+ m_use_public_queue = true;
+ if (success)
+ SetState (eStateDetached);
+ return success;
+}
+
+bool
+ProcessMacOSXRemote::DoKill (int signal)
+{
+ return Kill (signal);
+}
+
+
+//------------------------------------------------------------------
+// Thread Queries
+//------------------------------------------------------------------
+
+Thread *
+ProcessMacOSXRemote::GetCurrentThread ()
+{
+ return m_thread_list.GetCurrentThread().get();
+}
+
+ByteOrder
+ProcessMacOSXRemote::GetByteOrder () const
+{
+ return m_byte_order;
+}
+
+
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessMacOSXRemote::IsAlive ()
+{
+ return MachTask::IsValid (Task().TaskPort());
+}
+
+bool
+ProcessMacOSXRemote::IsRunning ()
+{
+ return LLDB_STATE_IS_RUNNING(GetState());
+}
+
+lldb::addr_t
+ProcessMacOSXRemote::GetImageInfoAddress()
+{
+ return Task().GetDYLDAllImageInfosAddress();
+}
+
+DynamicLoader *
+ProcessMacOSXRemote::GetDynamicLoader()
+{
+ return m_dynamic_loader_ap.get();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSXRemote::DoReadMemory (lldb::addr_t addr, void *buf, size_t size)
+{
+ return Task().ReadMemory(addr, buf, size);
+}
+
+size_t
+ProcessMacOSXRemote::DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size)
+{
+ return Task().WriteMemory(addr, buf, size);
+}
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSXRemote::GetSTDOUT (char *buf, size_t buf_size)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
+ Mutex::Locker locker(m_stdio_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.data(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.data(), bytes_available);
+ m_stdout_data.clear();
+ }
+ }
+ return bytes_available;
+}
+
+size_t
+ProcessMacOSXRemote::GetSTDERR (char *buf, size_t buf_size)
+{
+ return 0;
+}
+
+bool
+ProcessMacOSXRemote::EnableBreakpoint (BreakpointLocation *bp)
+{
+ assert (bp != NULL);
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ lldb::user_id_t breakID = bp->GetID();
+ lldb::addr_t addr = bp->GetAddress();
+ if (bp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessMacOSXRemote::EnableBreakpoint ( breakID = %d ) breakpoint already enabled.", breakID);
+ return true;
+ }
+ else
+ {
+ if (bp->HardwarePreferred())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp->GetThreadID()).get();
+ if (thread)
+ {
+ bp->SetHardwareIndex (thread->EnableHardwareBreakpoint(bp));
+ if (bp->IsHardware())
+ {
+ bp->SetEnabled(true);
+ return true;
+ }
+ }
+ }
+
+ const size_t break_op_size = GetSoftwareBreakpointTrapOpcode (bp);
+ assert (break_op_size > 0);
+ const uint8_t * const break_op = bp->GetTrapOpcodeBytes();
+
+ if (break_op_size > 0)
+ {
+ // Save the original opcode by reading it
+ if (m_task.ReadMemory(addr, bp->GetSavedOpcodeBytes(), break_op_size) == break_op_size)
+ {
+ // Write a software breakpoint in place of the original opcode
+ if (m_task.WriteMemory(addr, break_op, break_op_size) == break_op_size)
+ {
+ uint8_t verify_break_op[4];
+ if (m_task.ReadMemory(addr, verify_break_op, break_op_size) == break_op_size)
+ {
+ if (memcmp(break_op, verify_break_op, break_op_size) == 0)
+ {
+ bp->SetEnabled(true);
+ if (log)
+ log->Printf("ProcessMacOSXRemote::EnableBreakpoint ( breakID = %d ) SUCCESS.", breakID, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ GetError().SetErrorString("Failed to verify the breakpoint trap in memory.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to read memory to verify breakpoint trap.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to write breakpoint trap to memory.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to read memory at breakpoint address.");
+ }
+ }
+ }
+
+ if (log)
+ {
+ const char *err_string = GetError().AsCString();
+ log->Printf ("ProcessMacOSXRemote::EnableBreakpoint ( breakID = %d ) error: %s",
+ breakID, err_string ? err_string : "NULL");
+ }
+ GetError().SetErrorToGenericError();
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::DisableBreakpoint (BreakpointLocation *bp)
+{
+ assert (bp != NULL);
+ lldb::addr_t addr = bp->GetAddress();
+ lldb::user_id_t breakID = bp->GetID();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) addr = 0x%8.8llx", breakID, (uint64_t)addr);
+
+ if (bp->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->DisableHardwareBreakpoint(bp))
+ {
+ bp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) (hardware) => success", breakID);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ const size_t break_op_size = bp->GetByteSize();
+ assert (break_op_size > 0);
+ const uint8_t * const break_op = bp->GetTrapOpcodeBytes();
+ if (break_op_size > 0)
+ {
+ // Clear a software breakoint instruction
+ uint8_t curr_break_op[break_op_size];
+ bool break_op_found = false;
+
+ // Read the breakpoint opcode
+ if (m_task.ReadMemory(addr, curr_break_op, break_op_size) == break_op_size)
+ {
+ bool verify = false;
+ if (bp->IsEnabled())
+ {
+ // Make sure we have the a breakpoint opcode exists at this address
+ if (memcmp(curr_break_op, break_op, break_op_size) == 0)
+ {
+ break_op_found = true;
+ // We found a valid breakpoint opcode at this address, now restore
+ // the saved opcode.
+ if (m_task.WriteMemory(addr, bp->GetSavedOpcodeBytes(), break_op_size) == break_op_size)
+ {
+ verify = true;
+ }
+ else
+ {
+ GetError().SetErrorString("Memory write failed when restoring original opcode.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Original breakpoint trap is no longer in memory.");
+ // Set verify to true and so we can check if the original opcode has already been restored
+ verify = true;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) is already disabled", breakID);
+ // Set verify to true and so we can check if the original opcode is there
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode[break_op_size];
+ // Verify that our original opcode made it back to the inferior
+ if (m_task.ReadMemory(addr, verify_opcode, break_op_size) == break_op_size)
+ {
+ // compare the memory we just read with the original opcode
+ if (memcmp(bp->GetSavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
+ {
+ // SUCCESS
+ bp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) SUCCESS", breakID);
+ return true;
+ }
+ else
+ {
+ if (break_op_found)
+ GetError().SetErrorString("Failed to restore original opcode.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+ }
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to read memory that should contain the breakpoint trap.");
+ }
+ }
+
+ GetError().SetErrorToGenericError();
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::EnableWatchpoint (WatchpointLocation *wp)
+{
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+ lldb::addr_t addr = wp->GetAddress();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::EnableWatchpoint(watchID = %d)", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessMacOSXRemote::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ wp->SetHardwareIndex (thread->EnableHardwareWatchpoint (wp));
+ if (wp->IsHardware ())
+ {
+ wp->SetEnabled(true);
+ return true;
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Watchpoints currently only support thread specific watchpoints.");
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::DisableWatchpoint (WatchpointLocation *wp)
+{
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+
+ lldb::addr_t addr = wp->GetAddress();
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableWatchpoint (watchID = %d) addr = 0x%8.8llx", watchID, (uint64_t)addr);
+
+ if (wp->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->DisableHardwareWatchpoint (wp))
+ {
+ wp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::Disablewatchpoint (watchID = %d) addr = 0x%8.8llx (hardware) => success", watchID, (uint64_t)addr);
+ return true;
+ }
+ }
+ }
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ GetError().SetErrorString("Watchpoint location argument was NULL.");
+ }
+ GetError().SetErrorToGenericError();
+ return false;
+}
+
+
+static ProcessMacOSXRemote::CreateArchCalback
+ArchDCScriptInterpreter::TypeMap(const ArchSpec& arch_spec, ProcessMacOSXRemote::CreateArchCalback callback, bool add )
+{
+ // We must wrap the "g_arch_map" file static in a function to avoid
+ // any global constructors so we don't get a build verification error
+ typedef std::multimap<ArchSpec, ProcessMacOSXRemote::CreateArchCalback> ArchToProtocolMap;
+ static ArchToProtocolMap g_arch_map;
+
+ if (add)
+ {
+ g_arch_map.insert(std::make_pair(arch_spec, callback));
+ return callback;
+ }
+ else
+ {
+ ArchToProtocolMap::const_iterator pos = g_arch_map.find(arch_spec);
+ if (pos != g_arch_map.end())
+ {
+ return pos->second;
+ }
+ }
+ return NULL;
+}
+
+void
+ProcessMacOSXRemote::AddArchCreateDCScriptInterpreter::Type(const ArchSpec& arch_spec, CreateArchCalback callback)
+{
+ ArchDCScriptInterpreter::TypeMap (arch_spec, callback, true);
+}
+
+ProcessMacOSXRemote::CreateArchCalback
+ProcessMacOSXRemote::GetArchCreateDCScriptInterpreter::Type()
+{
+ return ArchDCScriptInterpreter::TypeMap (m_arch_spec, NULL, false);
+}
+
+void
+ProcessMacOSXRemote::Clear()
+{
+ // Clear any cached thread list while the pid and task are still valid
+
+ m_task.Clear();
+ // Now clear out all member variables
+ CloseChildFileDescriptors();
+
+ m_flags = eFlagsNone;
+ m_thread_list.Clear();
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ m_exception_messages.clear();
+ }
+
+}
+
+
+bool
+ProcessMacOSXRemote::Kill (int signal)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::Kill(signal = %d)", signal);
+ State state = GetState();
+
+ if (IsRunning(state))
+ {
+ if (::kill (GetID(), signal) == 0)
+ {
+ GetError().Clear();
+ }
+ else
+ {
+ GetError().SetErrorToErrno();
+ GetError().LogIfError(log, "ProcessMacOSXRemote::Kill(%d)", signal);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::Kill(signal = %d) pid %u (task = 0x%4.4x) was't running, ignoring...", signal, GetID(), m_task.TaskPort());
+ GetError().Clear();
+ }
+ return GetError().Success();
+
+}
+
+
+bool
+ProcessMacOSXRemote::Detach()
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::Detach()");
+
+ State state = GetState();
+
+ if (!IsRunning(state))
+ {
+ // Resume our process
+ PrivateResume(LLDB_INVALID_THREAD_ID);
+
+ // We have resumed and now we wait for that event to get posted
+ Event event;
+ if (WaitForPrivateEvents(LLDB_EVENT_RUNNING, &event, 2) == false)
+ return false;
+
+
+ // We need to be stopped in order to be able to detach, so we need
+ // to send ourselves a SIGSTOP
+ if (Kill(SIGSTOP))
+ {
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+
+ lldb::pid_t pid = GetID();
+ // Wait for our process stop event to get posted
+ if (WaitForPrivateEvents(LLDB_EVENT_STOPPED, &event, 2) == false)
+ {
+ GetError().Log(log, "::kill (pid = %u, SIGSTOP)", pid);
+ return false;
+ }
+
+ // Shut down the exception thread and cleanup our exception remappings
+ m_task.ShutDownExceptionThread();
+
+ // Detach from our process while we are stopped.
+ errno = 0;
+
+ // Detach from our process
+ ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
+
+ GetError().SetErrorToErrno();
+
+ if (log || GetError().Fail())
+ GetError().Log(log, "::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
+
+ // Resume our task
+ m_task.Resume();
+
+ // NULL our task out as we have already retored all exception ports
+ m_task.Clear();
+
+ // Clear out any notion of the process we once were
+ Clear();
+ }
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::Detach() error: process must be stopped (SIGINT the process first).");
+ }
+ return false;
+}
+
+
+
+void
+ProcessMacOSXRemote::ReplyToAllExceptions()
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+ if (m_exception_messages.empty() == false)
+ {
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+
+ MachException::Message::iterator pos;
+ MachException::Message::iterator begin = m_exception_messages.begin();
+ MachException::Message::iterator end = m_exception_messages.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (log)
+ log->Printf ("Replying to exception %d...", std::distance(begin, pos));
+ int resume_signal = 0;
+ ThreadSP thread_sp = m_thread_list.FindThreadByID(pos->state.thread_port);
+ if (thread_sp.get())
+ resume_signal = thread_sp->GetResumeSignal();
+ GetError() = pos->Reply (Task().TaskPort(), GetID(), resume_signal);
+ GetError().LogIfError(log, "Error replying to exception");
+ }
+
+ // Erase all exception message as we should have used and replied
+ // to them all already.
+ m_exception_messages.clear();
+ }
+}
+void
+ProcessMacOSXRemote::PrivateResume (lldb::tid_t tid)
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ReplyToAllExceptions();
+
+ // Let the thread prepare to resume and see if any threads want us to
+ // step over a breakpoint instruction (ProcessWillResume will modify
+ // the value of stepOverBreakInstruction).
+ //StateType process_state = m_thread_list.ProcessWillResume(this);
+
+ // Set our state accordingly
+ SetState(eStateRunning);
+
+ // Now resume our task.
+ GetError() = m_task.Resume();
+
+}
+
+// Called by the exception thread when an exception has been received from
+// our process. The exception message is completely filled and the exception
+// data has already been copied.
+void
+ProcessMacOSXRemote::ExceptionMessageReceived (const MachException::Message& exceptionMessage)
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+
+ if (m_exception_messages.empty())
+ m_task.Suspend();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "ProcessMacOSXRemote::ExceptionMessageReceived ( )");
+
+ // Use a locker to automatically unlock our mutex in case of exceptions
+ // Add the exception to our internal exception stack
+ m_exception_messages.push_back(exceptionMessage);
+}
+
+
+//bool
+//ProcessMacOSXRemote::GetProcessInfo (struct kinfo_proc* proc_info)
+//{
+// int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, GetID() };
+// size_t buf_size = sizeof(struct kinfo_proc);
+//
+// if (::sysctl (mib, (unsigned)(sizeof(mib)/sizeof(int)), &proc_info, &buf_size, NULL, 0) == 0)
+// return buf_size > 0;
+//
+// return false;
+//}
+//
+//
+void
+ProcessMacOSXRemote::ExceptionMessageBundleComplete()
+{
+ // We have a complete bundle of exceptions for our child process.
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s: %d exception messages.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ if (!m_exception_messages.empty())
+ {
+ SetState (eStateStopped);
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s empty exception messages bundle.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ }
+}
+
+bool
+ProcessMacOSXRemote::ReleaseChildFileDescriptors ( int *stdin_fileno, int *stdout_fileno, int *stderr_fileno )
+{
+ if (stdin_fileno)
+ *stdin_fileno = m_child_stdin;
+ if (stdout_fileno)
+ *stdout_fileno = m_child_stdout;
+ if (stderr_fileno)
+ *stderr_fileno = m_child_stderr;
+ // Stop the stdio thread if we have one, but don't have it close the child
+ // file descriptors since we are giving control of these descriptors to the
+ // caller
+ bool close_child_fds = false;
+ StopSTDIOThread(close_child_fds);
+ return true;
+}
+
+void
+ProcessMacOSXRemote::AppendSTDOUT (char* s, size_t len)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::%s (<%d> %s) ...", __FUNCTION__, len, s);
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.append(s, len);
+ AppendEvent (LLDB_EVENT_STDIO);
+}
+
+void *
+ProcessMacOSXRemote::STDIOThread(void *arg)
+{
+ ProcessMacOSXRemote *proc = (ProcessMacOSXRemote*) arg;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::%s (arg = %p) thread starting...", __FUNCTION__, arg);
+
+ // We start use a base and more options so we can control if we
+ // are currently using a timeout on the mach_msg. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main thread loop
+ // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ Error err;
+ int stdout_fd = proc->GetStdoutFileDescriptor();
+ int stderr_fd = proc->GetStderrFileDescriptor();
+ if (stdout_fd == stderr_fd)
+ stderr_fd = -1;
+
+ while (stdout_fd >= 0 || stderr_fd >= 0)
+ {
+ ::pthread_testcancel ();
+
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ if (stdout_fd >= 0)
+ FD_SET (stdout_fd, &read_fds);
+ if (stderr_fd >= 0)
+ FD_SET (stderr_fd, &read_fds);
+ int nfds = std::max<int>(stdout_fd, stderr_fd) + 1;
+
+ int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL);
+ if (log)
+ log->Printf("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+
+ if (num_set_fds < 0)
+ {
+ int select_errno = errno;
+ if (log)
+ {
+ err.SetError (select_errno, Error::POSIX);
+ err.LogIfError(log, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+ }
+
+ switch (select_errno)
+ {
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO
+ break;
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return NULL;
+ break;
+ case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred.
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ break;
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ }
+ else
+ {
+ char s[1024];
+ s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination
+ int bytes_read = 0;
+ if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stdout_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d (reached EOF for child STDOUT)", bytes_read);
+ stdout_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+
+ if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stderr_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d (reached EOF for child STDERR)", bytes_read);
+ stderr_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+ }
+ }
+
+ if (log)
+ log->Printf("ProcessMacOSXRemote::%s (%p): thread exiting...", __FUNCTION__, arg);
+
+ return NULL;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::AttachForDebug (lldb::pid_t pid)
+{
+ // Clear out and clean up from any current state
+ Clear();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (pid != 0)
+ {
+ SetState(eStateAttaching);
+ SetID(pid);
+ // Let ourselves know we are going to be using SBS if the correct flag bit is set...
+#if defined (__arm__)
+ if (IsSBProcess(pid))
+ m_flags |= eFlagsUsingSBS;
+#endif
+ m_task.StartExceptionThread(GetError());
+
+ if (GetError().Success())
+ {
+ if (ptrace (PT_ATTACHEXC, pid, 0, 0) == 0)
+ {
+ m_flags.Set (eFlagsAttached);
+ // Sleep a bit to let the exception get received and set our process status
+ // to stopped.
+ ::usleep(250000);
+ if (log)
+ log->Printf ("successfully attached to pid %d", pid);
+ return GetID();
+ }
+ else
+ {
+ GetError().SetErrorToErrno();
+ if (log)
+ log->Printf ("error: failed to attach to pid %d", pid);
+ }
+ }
+ else
+ {
+ GetError().Log(log, "ProcessMacOSXRemote::%s (pid = %i) failed to start exception thread", __FUNCTION__, pid);
+ }
+ }
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::LaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ PDLaunchType launch_type,
+ Error &launch_err)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ m_arch_spec = arch_spec;
+
+ if (launch_type == eLaunchDefault)
+ launch_type = eLaunchPosixSpawn;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s( path = '%s', argv = %p, envp = %p, launch_type = %u )", __FUNCTION__, path, argv, envp, launch_type);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+ switch (launch_type)
+ {
+ case eLaunchForkExec:
+ SetID(ProcessMacOSXRemote::ForkChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+ case eLaunchPosixSpawn:
+ SetID(ProcessMacOSXRemote::PosixSpawnChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+#if defined (__arm__)
+
+ case eLaunchSpringBoard:
+ {
+ const char *app_ext = strstr(path, ".app");
+ if (app_ext != NULL)
+ {
+ std::string app_bundle_path(path, app_ext + strlen(".app"));
+ return SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, launch_err);
+ }
+ }
+ break;
+
+#endif
+
+ default:
+ // Invalid launch
+ launch_err.SetErrorToGenericError ();
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+ lldb::pid_t pid = GetID();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we don't have a valid process ID and no one has set the error,
+ // then return a generic error
+ if (launch_err.Success())
+ launch_err.SetErrorToGenericError ();
+ }
+ else
+ {
+ // Make sure we can get our task port before going any further
+ m_task.TaskPortForProcessID (launch_err);
+
+ // If that goes well then kick off our exception thread
+ if (launch_err.Success())
+ m_task.StartExceptionThread(launch_err);
+
+ if (launch_err.Success())
+ {
+ //m_path = path;
+// size_t i;
+// if (argv)
+// {
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+// }
+
+ StartSTDIOThread();
+
+ if (launch_type == eLaunchPosixSpawn)
+ {
+
+ //SetState (eStateAttaching);
+ errno = 0;
+ if (::ptrace (PT_ATTACHEXC, pid, 0, 0) == 0)
+ launch_err.Clear();
+ else
+ launch_err.SetErrorToErrno();
+
+ if (launch_err.Fail() || log)
+ launch_err.Log(log, "::ptrace (PT_ATTACHEXC, pid = %i, 0, 0 )", pid);
+
+ if (launch_err.Success())
+ m_flags.Set (eFlagsAttached);
+ else
+ SetState (eStateExited);
+ }
+ else
+ {
+ launch_err.Clear();
+ }
+ }
+ else
+ {
+ // We were able to launch the process, but not get its task port
+ // so now we need to make it sleep with da fishes.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ ::kill (pid, SIGCONT);
+ ::kill (pid, SIGKILL);
+ pid = LLDB_INVALID_PROCESS_ID;
+ }
+
+ }
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::PosixSpawnChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSXRemote* process,
+ Error &err
+)
+{
+ posix_spawnattr_t attr;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+
+ Error local_err; // Errors that don't affect the spawning.
+ if (log)
+ log->Printf ("%s ( path='%s', argv=%p, envp=%p, process )", __FUNCTION__, path, argv, envp);
+ err.SetError( ::posix_spawnattr_init (&attr), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnattr_init ( &attr )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+ err.SetError( ::posix_spawnattr_setflags (&attr, POSIX_SPAWN_START_SUSPENDED), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+#if !defined(__arm__)
+
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ cpu_type_t cpu = arch_spec.GetCPUType();
+ if (cpu != 0 && cpu != CPU_TYPE_ANY && cpu != LLDB_INVALID_CPUTYPE)
+ {
+ size_t ocount = 0;
+ err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu, ocount);
+
+ if (err.Fail() != 0 || ocount != 1)
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+#endif
+
+ PseudoTerminal pty;
+
+ posix_spawn_file_actions_t file_actions;
+ err.SetError( ::posix_spawn_file_actions_init (&file_actions), Error::POSIX);
+ int file_actions_valid = err.Success();
+ if (!file_actions_valid || log)
+ err.Log(log, "::posix_spawn_file_actions_init ( &file_actions )");
+ Error stdio_err;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (file_actions_valid)
+ {
+ // If the user specified any STDIO files, then use those
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stderr_path != NULL && stderr_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, stderr_path, O_RDWR, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR, mode = 0 )", stderr_path);
+ }
+
+ if (stdin_path != NULL && stdin_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, stdin_path, O_RDONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY, mode = 0 )", stdin_path);
+ }
+
+ if (stdout_path != NULL && stdout_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, stdout_path, O_WRONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY, mode = 0 )", stdout_path);
+ }
+ }
+ else
+ {
+ // The user did not specify any STDIO files, use a pseudo terminal.
+ // Callers can then access the file handles using the
+ // ProcessMacOSXRemote::ReleaseChildFileDescriptors() function, otherwise
+ // this class will spawn a thread that tracks STDIO and buffers it.
+ process->SetSTDIOIsOurs(true);
+ if (pty.OpenFirstAvailableMaster(O_RDWR, &stdio_err))
+ {
+ const char* slave_name = pty.GetSlaveName(&stdio_err);
+ if (slave_name == NULL)
+ slave_name = "/dev/null";
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, slave_name, O_RDWR, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, slave_name, O_RDONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, slave_name, O_WRONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY, mode = 0 )", slave_name);
+ }
+ }
+ err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp);
+
+ if (stdio_err.Success())
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ else
+ {
+ err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp);
+ }
+
+ // We have seen some cases where posix_spawnp was returning a valid
+ // looking pid even when an error was returned, so clear it out
+ if (err.Fail())
+ pid = LLDB_INVALID_PROCESS_ID;
+
+ if (file_actions_valid)
+ {
+ local_err.SetError( ::posix_spawn_file_actions_destroy (&file_actions), Error::POSIX);
+ if (local_err.Fail() || log)
+ local_err.Log(log, "::posix_spawn_file_actions_destroy ( &file_actions )");
+ }
+
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::ForkChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSXRemote* process,
+ Error &launch_err
+)
+{
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ assert(!"TODO: ForkChildForPTraceDebugging doesn't currently support fork/exec with user file handles...");
+ }
+ else
+ {
+
+ // Use a fork that ties the child process's stdin/out/err to a pseudo
+ // terminal so we can read it in our ProcessMacOSXRemote::STDIOThread
+ // as unbuffered io.
+ PseudoTerminal pty;
+ pid = pty.Fork(&launch_err);
+
+ if (pid < 0)
+ {
+ //--------------------------------------------------------------
+ // Error during fork.
+ //--------------------------------------------------------------
+ return pid;
+ }
+ else if (pid == 0)
+ {
+ //--------------------------------------------------------------
+ // Child process
+ //--------------------------------------------------------------
+ ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process
+ ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions
+
+ // If our parent is setgid, lets make sure we don't inherit those
+ // extra powers due to nepotism.
+ ::setgid (getgid ());
+
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (0, 0); // Set the child process group to match its pid
+
+ // Sleep a bit to before the exec call
+ ::sleep (1);
+
+ // Turn this process into
+ ::execv (path, (char * const *)argv);
+ // Exit with error code. Child process should have taken
+ // over in above exec call and if the exec fails it will
+ // exit the child process below.
+ ::exit (127);
+ }
+ else
+ {
+ //--------------------------------------------------------------
+ // Parent process
+ //--------------------------------------------------------------
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (pid, pid); // Set the child process group to match its pid
+
+ if (process != NULL)
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ return pid;
+}
+
+#if defined (__arm__)
+
+lldb::pid_t
+ProcessMacOSXRemote::SBLaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ Error &launch_err
+)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+ m_pid = ProcessMacOSXRemote::SBLaunchForDebug(path, argv, envp, this, launch_err);
+ if (m_pid != 0)
+ {
+ m_flags |= eFlagsUsingSBS;
+ //m_path = path;
+// size_t i;
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+ m_task.StartExceptionThread();
+ StartSTDIOThread();
+ SetState (eStateAttaching);
+ int err = ptrace (PT_ATTACHEXC, m_pid, 0, 0);
+ if (err == 0)
+ {
+ m_flags |= eFlagsAttached;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "successfully attached to pid %d", m_pid);
+ }
+ else
+ {
+ SetState (eStateExited);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "error: failed to attach to pid %d", m_pid);
+ }
+ }
+ return m_pid;
+}
+
+#include <servers/bootstrap.h>
+#include "CFBundle.h"
+#include "CFData.h"
+#include "CFString.h"
+
+lldb::pid_t
+ProcessMacOSXRemote::SBLaunchForDebug
+(
+ const char *app_bundle_path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSXRemote* process,
+ Error &launch_err
+)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process);
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ if (argv[0] == NULL)
+ return LLDB_INVALID_PROCESS_ID;
+
+ size_t argc = 0;
+ // Count the number of arguments
+ while (argv[argc] != NULL)
+ argc++;
+
+ // Enumerate the arguments
+ size_t first_launch_arg_idx = 1;
+ CFReleaser<CFMutableArrayRef> launch_argv;
+
+ if (argv[first_launch_arg_idx])
+ {
+ size_t launch_argc = argc > 0 ? argc - 1 : 0;
+ launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks));
+ size_t i;
+ char const *arg;
+ CFString launch_arg;
+ for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++)
+ {
+ launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8));
+ if (launch_arg.get() != NULL)
+ CFArrayAppendValue(launch_argv.get(), launch_arg.get());
+ else
+ break;
+ }
+ }
+
+ // Next fill in the arguments dictionary. Note, the envp array is of the form
+ // Variable=value but SpringBoard wants a CF dictionary. So we have to convert
+ // this here.
+
+ CFReleaser<CFMutableDictionaryRef> launch_envp;
+
+ if (envp[0])
+ {
+ launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ const char *value;
+ int name_len;
+ CFString name_string, value_string;
+
+ for (int i = 0; envp[i] != NULL; i++)
+ {
+ value = strstr (envp[i], "=");
+
+ // If the name field is empty or there's no =, skip it. Somebody's messing with us.
+ if (value == NULL || value == envp[i])
+ continue;
+
+ name_len = value - envp[i];
+
+ // Now move value over the "="
+ value++;
+
+ name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false));
+ value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8));
+ CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get());
+ }
+ }
+
+ CFString stdout_cf_path;
+ CFString stderr_cf_path;
+ PseudoTerminal pty;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stdout_path)
+ stdout_cf_path.SetFileSystemRepresentation (stdout_path);
+ if (stderr_path)
+ stderr_cf_path.SetFileSystemRepresentation (stderr_path);
+ }
+ else
+ {
+ process->SetSTDIOIsOurs(true);
+ PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR);
+ if (pty_err == PseudoTerminal::success)
+ {
+ const char* slave_name = pty.SlaveName();
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name);
+ if (slave_name && slave_name[0])
+ {
+ ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO);
+ stdout_cf_path.SetFileSystemRepresentation (slave_name);
+ stderr_cf_path.(stdout_cf_path);
+ }
+ }
+ }
+
+ if (stdout_cf_path.get() == NULL)
+ stdout_cf_path.SetFileSystemRepresentation ("/dev/null");
+ if (stderr_cf_path.get() == NULL)
+ stderr_cf_path.SetFileSystemRepresentation ("/dev/null");
+
+ CFBundle bundle(app_bundle_path);
+ CFStringRef bundleIDCFStr = bundle.GetIdentifier();
+ std::string bundleID;
+ if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
+ {
+ struct stat app_bundle_stat;
+ if (::stat (app_bundle_path, &app_bundle_stat) < 0)
+ {
+ launch_err.SetError(errno, Error::POSIX);
+ launch_err.SetErrorStringWithFormat ("%s: \"%s\".\n", launch_err.AsString(), app_bundle_path);
+ }
+ else
+ {
+ launch_err.SetError(-1, Error::Generic);
+ launch_err.SetErrorStringWithFormat ("Failed to extract CFBundleIdentifier from %s.\n", app_bundle_path);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
+
+
+ CFData argv_data(NULL);
+
+ if (launch_argv.get())
+ {
+ if (argv_data.Serialize(launch_argv.get(), kCFPropertyListBinaryFormat_v1_0) == NULL)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: failed to serialize launch arg array...", __FUNCTION__);
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__);
+
+ // Find SpringBoard
+ SBSApplicationLaunchError sbs_error = 0;
+ sbs_error = SBSLaunchApplication ( bundleIDCFStr,
+ (CFURLRef)NULL, // openURL
+ launch_argv.get(),
+ launch_envp.get(), // CFDictionaryRef environment
+ stdout_cf_path.get(),
+ stderr_cf_path.get(),
+ SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice);
+
+
+ launch_err.SetError(sbs_error, Error::SpringBoard);
+
+ if (sbs_error == SBSApplicationLaunchErrorSuccess)
+ {
+ static const useconds_t pid_poll_interval = 200000;
+ static const useconds_t pid_poll_timeout = 30000000;
+
+ useconds_t pid_poll_total = 0;
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired
+ // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started
+ // yet, or that it died very quickly (if you weren't using waitForDebugger).
+ while (!pid_found && pid_poll_total < pid_poll_timeout)
+ {
+ usleep (pid_poll_interval);
+ pid_poll_total += pid_poll_interval;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str());
+ pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ }
+
+ if (pid_found)
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFD();
+ process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid);
+ }
+ else
+ {
+ LogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str());
+ }
+ return pid;
+ }
+
+ LogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error);
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+#endif // #if defined (__arm__)
+
diff --git a/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.h b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.h
new file mode 100644
index 0000000..01905c6
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.h
@@ -0,0 +1,206 @@
+//===-- ProcessMacOSXRemote.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// ProcessMacOSXRemote.h
+// liblldb
+//
+// Created by Greg Clayton on 4/21/09.
+//
+//
+//----------------------------------------------------------------------
+
+#ifndef liblldb_ProcessMacOSXRemote_H_
+#define liblldb_ProcessMacOSXRemote_H_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+class ThreadMacOSXRemote;
+
+class ProcessMacOSXRemote :
+ public Process
+{
+public:
+ friend class ThreadMacOSX;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessMacOSXRemote(Target& target);
+ virtual ~DCProcessMacOSXRemote();
+
+ static Process* CreateInstance (Target& target);
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool CanDebug(Target &target);
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb::pid_t DoLaunch (Module* module,
+ char const *argv[], // Can be NULL
+ char const *envp[], // Can be NULL
+ const char *stdin_path, // Can be NULL
+ const char *stdout_path, // Can be NULL
+ const char *stderr_path); // Can be NULL
+ virtual void DidLaunch ();
+ virtual lldb::pid_t DoAttach (lldb::pid_t pid);
+ virtual void DidAttach ();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+// virtual bool WillResume ();
+ virtual bool DoResume ();
+// virtual void DidResume ();
+
+ virtual bool DoHalt ();
+ virtual bool WillDetach ();
+ virtual bool DoDetach ();
+ virtual bool DoKill (int signal);
+
+ virtual bool ShouldStop ();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool IsAlive ();
+ virtual bool IsRunning ();
+ virtual lldb::addr_t GetImageInfoAddress();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t DoReadMemory (lldb::addr_t addr, void *buf, size_t size);
+ virtual size_t DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t GetSTDOUT (char *buf, size_t buf_size);
+ virtual size_t GetSTDERR (char *buf, size_t buf_size);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual bool
+ EnableBreakpoint (lldb::BreakpointSite *bp_site);
+
+ virtual bool
+ DisableBreakpoint (lldb::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual bool EnableWatchpoint (WatchpointLocation *wp_loc);
+ virtual bool DisableWatchpoint (WatchpointLocation *wp_loc);
+
+ //------------------------------------------------------------------
+ // Thread Queries
+ //------------------------------------------------------------------
+ virtual Thread * GetCurrentThread ();
+ virtual bool SetCurrentThread (lldb::tid_t tid);
+ virtual Thread * GetThreadAtIndex (uint32_t idx);
+ virtual Thread * GetThreadByID (lldb::tid_t tid);
+ virtual size_t GetNumThreads ();
+
+ virtual ByteOrder GetByteOrder () const;
+
+ virtual DynamicLoader *
+ GetDynamicLoader ();
+
+protected:
+ Flags m_flags; // Process specific flags (see eFlags enums)
+ ArchSpec m_arch_spec;
+ std::auto_ptr<DynamicLoader> m_dynamic_loader_ap;
+ ByteOrder m_byte_order;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ ProcessIDIsValid ( ) const;
+
+ bool
+ IsRunning ( State state )
+ {
+ return state == eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( State state)
+ {
+ return state == eStateStepping;
+ }
+ bool
+ CanResume ( State state)
+ {
+ return state == eStateStopped;
+ }
+
+ ArchSpec&
+ GetArchSpec()
+ {
+ return m_arch_spec;
+ }
+ const ArchSpec&
+ GetArchSpec() const
+ {
+ return m_arch_spec;
+ }
+
+ enum
+ {
+ eFlagsNone = 0,
+ eFlagsAttached = (1 << 0),
+ eFlagsUsingSBS = (1 << 1)
+ };
+
+ void
+ Clear ( );
+
+ Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ uint32_t
+ UpdateThreadListIfNeeded ();
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessMacOSXRemote only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ProcessMacOSXRemote);
+
+};
+
+#endif // liblldb_ProcessMacOSXRemote_H_
diff --git a/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.cpp b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.cpp
new file mode 100644
index 0000000..3747254
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.cpp
@@ -0,0 +1,1448 @@
+//===-- RegisterContextMach_arm.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMach_arm.h"
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Scalar.h"
+
+// Project includes
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_r0 = 0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13, gpr_sp = gpr_r13,
+ gpr_r14, gpr_lr = gpr_r14,
+ gpr_r15, gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, StackFrame *frame) :
+ RegisterContext(thread, frame),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextMach_arm::~RegisterContextMach_arm()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextMach_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextMach_arm::GPR) + sizeof (RegisterContextMach_arm::FPU))
+#define DBG_OFFSET(reg) (offsetof (RegisterContextMach_arm::DBG, reg) + sizeof (RegisterContextMach_arm::GPR) + sizeof (RegisterContextMach_arm::FPU) + sizeof (RegisterContextMach_arm::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextMach_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, dbg_##reg##i, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextMach_arm::GPR) + sizeof (RegisterContextMach_arm::FPU) + sizeof (RegisterContextMach_arm::EXC))
+// General purpose registers
+static lldb::RegisterInfo
+g_register_infos[] =
+{
+// NAME ALT SZ OFFSET ENCODING FORMAT NATIVE COMPILER DWARF GENERIC
+// ====== ======= == ============= ============= ============ ========== =============== =============== =========
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, gpr_r0, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM }},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, gpr_r1, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM }},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, gpr_r2, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM }},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, gpr_r3, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM }},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, gpr_r4, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM }},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, gpr_r5, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM }},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, gpr_r6, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM }},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, gpr_r7, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP }},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, gpr_r8, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM }},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, gpr_r9, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM }},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, gpr_r10, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM }},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, gpr_r11, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM }},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, gpr_r12, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM }},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, gpr_sp, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP }},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, gpr_lr, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA }},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, gpr_pc, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC }},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, gpr_cpsr, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS }},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, fpu_s0, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM }},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, fpu_s1, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM }},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, fpu_s2, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM }},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, fpu_s3, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM }},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, fpu_s4, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM }},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, fpu_s5, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM }},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, fpu_s6, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM }},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, fpu_s7, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM }},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, fpu_s8, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM }},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, fpu_s9, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM }},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, fpu_s10, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM }},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, fpu_s11, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM }},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, fpu_s12, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM }},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, fpu_s13, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM }},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, fpu_s14, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM }},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, fpu_s15, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM }},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, fpu_s16, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM }},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, fpu_s17, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM }},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, fpu_s18, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM }},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, fpu_s19, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM }},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, fpu_s20, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM }},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, fpu_s21, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM }},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, fpu_s22, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM }},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, fpu_s23, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM }},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, fpu_s24, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM }},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, fpu_s25, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM }},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, fpu_s26, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM }},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, fpu_s27, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM }},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, fpu_s28, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM }},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, fpu_s29, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM }},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, fpu_s30, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM }},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, fpu_s31, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM }},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, fpu_fpscr, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, exc_exception,{ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, exc_fsr, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, exc_far, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 1) },
+{ DEFINE_DBG (bvr, 2) },
+{ DEFINE_DBG (bvr, 3) },
+{ DEFINE_DBG (bvr, 4) },
+{ DEFINE_DBG (bvr, 5) },
+{ DEFINE_DBG (bvr, 6) },
+{ DEFINE_DBG (bvr, 7) },
+{ DEFINE_DBG (bvr, 8) },
+{ DEFINE_DBG (bvr, 9) },
+{ DEFINE_DBG (bvr, 10) },
+{ DEFINE_DBG (bvr, 11) },
+{ DEFINE_DBG (bvr, 12) },
+{ DEFINE_DBG (bvr, 13) },
+{ DEFINE_DBG (bvr, 14) },
+{ DEFINE_DBG (bvr, 15) },
+
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 1) },
+{ DEFINE_DBG (bcr, 2) },
+{ DEFINE_DBG (bcr, 3) },
+{ DEFINE_DBG (bcr, 4) },
+{ DEFINE_DBG (bcr, 5) },
+{ DEFINE_DBG (bcr, 6) },
+{ DEFINE_DBG (bcr, 7) },
+{ DEFINE_DBG (bcr, 8) },
+{ DEFINE_DBG (bcr, 9) },
+{ DEFINE_DBG (bcr, 10) },
+{ DEFINE_DBG (bcr, 11) },
+{ DEFINE_DBG (bcr, 12) },
+{ DEFINE_DBG (bcr, 13) },
+{ DEFINE_DBG (bcr, 14) },
+{ DEFINE_DBG (bcr, 15) },
+
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 1) },
+{ DEFINE_DBG (wvr, 2) },
+{ DEFINE_DBG (wvr, 3) },
+{ DEFINE_DBG (wvr, 4) },
+{ DEFINE_DBG (wvr, 5) },
+{ DEFINE_DBG (wvr, 6) },
+{ DEFINE_DBG (wvr, 7) },
+{ DEFINE_DBG (wvr, 8) },
+{ DEFINE_DBG (wvr, 9) },
+{ DEFINE_DBG (wvr, 10) },
+{ DEFINE_DBG (wvr, 11) },
+{ DEFINE_DBG (wvr, 12) },
+{ DEFINE_DBG (wvr, 13) },
+{ DEFINE_DBG (wvr, 14) },
+{ DEFINE_DBG (wvr, 15) },
+
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 1) },
+{ DEFINE_DBG (wcr, 2) },
+{ DEFINE_DBG (wcr, 3) },
+{ DEFINE_DBG (wcr, 4) },
+{ DEFINE_DBG (wcr, 5) },
+{ DEFINE_DBG (wcr, 6) },
+{ DEFINE_DBG (wcr, 7) },
+{ DEFINE_DBG (wcr, 8) },
+{ DEFINE_DBG (wcr, 9) },
+{ DEFINE_DBG (wcr, 10) },
+{ DEFINE_DBG (wcr, 11) },
+{ DEFINE_DBG (wcr, 12) },
+{ DEFINE_DBG (wcr, 13) },
+{ DEFINE_DBG (wcr, 14) },
+{ DEFINE_DBG (wcr, 15) }
+};
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_r0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_sp,
+ gpr_lr,
+ gpr_pc,
+ gpr_cpsr
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_exception,
+ exc_fsr,
+ exc_far,
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextMach_arm::Invalidate ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextMach_arm::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextMach_arm::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextMach_arm::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextMach_arm::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextMach_arm::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextMach_arm::GetRegisterSet (uint32_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextMach_arm::GetSetForNativeRegNum (int reg)
+{
+ if (reg < fpu_s0)
+ return GPRRegSet;
+ else if (reg < exc_exception)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = GPRWordCount;
+ SetError(GPRRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&gpr, &count));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = FPUWordCount;
+ SetError(FPURegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&fpu, &count));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = EXCWordCount;
+ SetError(EXCRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&exc, &count));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = DBGWordCount;
+ SetError(DBGRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&dbg, &count));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(GPRRegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&gpr, GPRWordCount));
+ return GetError(GPRRegSet, Write);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(FPURegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&fpu, FPUWordCount));
+ return GetError(FPURegSet, Write);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(EXCRegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&exc, EXCWordCount));
+ return GetError(EXCRegSet, Write);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(DBGRegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&dbg, DBGWordCount));
+ return GetError(DBGRegSet, Write);
+}
+
+
+kern_return_t
+RegisterContextMach_arm::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ case DBGRegSet: return ReadDBG(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ case DBGRegSet: return WriteDBG();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void
+RegisterContextMach_arm::LogDBGRegisters (Log *log, const DBG& dbg)
+{
+ if (log)
+ {
+ for (uint32_t i=0; i<16; i++)
+ log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }",
+ i, i, dbg.bvr[i], dbg.bcr[i],
+ i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+
+bool
+RegisterContextMach_arm::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ int set = RegisterContextMach_arm::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ value = gpr.r[reg - gpr_r0];
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ value = fpu.floats.s[reg];
+ break;
+
+ case fpu_fpscr:
+ value = fpu.fpscr;
+ break;
+
+ case exc_exception:
+ value = exc.exception;
+ break;
+ case exc_fsr:
+ value = exc.fsr;
+ break;
+ case exc_far:
+ value = exc.far;
+ break;
+
+ default:
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextMach_arm::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.r[reg - gpr_r0] = value.UInt(0);
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ fpu.floats.s[reg] = value.UInt(0);
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.UInt(0);
+ break;
+
+ case exc_exception:
+ exc.exception = value.UInt(0);
+ break;
+ case exc_fsr:
+ exc.fsr = value.UInt(0);
+ break;
+ case exc_far:
+ exc.far = value.UInt(0);
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_arm::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ int set = RegisterContextMach_arm::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ data.SetData(&gpr.r[reg - gpr_r0], reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ data.SetData(&fpu.floats.s[reg - fpu_s0], reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fpscr:
+ data.SetData(&fpu.fpscr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_exception:
+ data.SetData(&exc.exception, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_fsr:
+ data.SetData(&exc.fsr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_far:
+ data.SetData(&exc.far, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool
+RegisterContextMach_arm::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL && data.ValidOffsetForDataOfSize(data_offset, reg_info->byte_size))
+ return false;
+
+ uint32_t offset = data_offset;
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.r[reg - gpr_r0] = data.GetU32 (&offset);
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ fpu.floats.s[reg - fpu_s0] = data.GetU32 (&offset);
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = data.GetU32 (&offset);
+ break;
+
+ case exc_exception:
+ fpu.fpscr = data.GetU32 (&offset);
+ break;
+
+ case exc_fsr:
+ exc.fsr = data.GetU32 (&offset);
+ break;
+
+ case exc_far:
+ exc.far = data.GetU32 (&offset);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextMach_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextMach_arm::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_r7;
+ case LLDB_REGNUM_GENERIC_RA: return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_r0: return gpr_r0;
+ case dwarf_r1: return gpr_r1;
+ case dwarf_r2: return gpr_r2;
+ case dwarf_r3: return gpr_r3;
+ case dwarf_r4: return gpr_r4;
+ case dwarf_r5: return gpr_r5;
+ case dwarf_r6: return gpr_r6;
+ case dwarf_r7: return gpr_r7;
+ case dwarf_r8: return gpr_r8;
+ case dwarf_r9: return gpr_r9;
+ case dwarf_r10: return gpr_r10;
+ case dwarf_r11: return gpr_r11;
+ case dwarf_r12: return gpr_r12;
+ case dwarf_sp: return gpr_sp;
+ case dwarf_lr: return gpr_lr;
+ case dwarf_pc: return gpr_pc;
+ case dwarf_spsr: return gpr_cpsr;
+
+ case dwarf_s0: return fpu_s0;
+ case dwarf_s1: return fpu_s1;
+ case dwarf_s2: return fpu_s2;
+ case dwarf_s3: return fpu_s3;
+ case dwarf_s4: return fpu_s4;
+ case dwarf_s5: return fpu_s5;
+ case dwarf_s6: return fpu_s6;
+ case dwarf_s7: return fpu_s7;
+ case dwarf_s8: return fpu_s8;
+ case dwarf_s9: return fpu_s9;
+ case dwarf_s10: return fpu_s10;
+ case dwarf_s11: return fpu_s11;
+ case dwarf_s12: return fpu_s12;
+ case dwarf_s13: return fpu_s13;
+ case dwarf_s14: return fpu_s14;
+ case dwarf_s15: return fpu_s15;
+ case dwarf_s16: return fpu_s16;
+ case dwarf_s17: return fpu_s17;
+ case dwarf_s18: return fpu_s18;
+ case dwarf_s19: return fpu_s19;
+ case dwarf_s20: return fpu_s20;
+ case dwarf_s21: return fpu_s21;
+ case dwarf_s22: return fpu_s22;
+ case dwarf_s23: return fpu_s23;
+ case dwarf_s24: return fpu_s24;
+ case dwarf_s25: return fpu_s25;
+ case dwarf_s26: return fpu_s26;
+ case dwarf_s27: return fpu_s27;
+ case dwarf_s28: return fpu_s28;
+ case dwarf_s29: return fpu_s29;
+ case dwarf_s30: return fpu_s30;
+ case dwarf_s31: return fpu_s31;
+
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC)
+ {
+ switch (reg)
+ {
+ case gcc_r0: return gpr_r0;
+ case gcc_r1: return gpr_r1;
+ case gcc_r2: return gpr_r2;
+ case gcc_r3: return gpr_r3;
+ case gcc_r4: return gpr_r4;
+ case gcc_r5: return gpr_r5;
+ case gcc_r6: return gpr_r6;
+ case gcc_r7: return gpr_r7;
+ case gcc_r8: return gpr_r8;
+ case gcc_r9: return gpr_r9;
+ case gcc_r10: return gpr_r10;
+ case gcc_r11: return gpr_r11;
+ case gcc_r12: return gpr_r12;
+ case gcc_sp: return gpr_sp;
+ case gcc_lr: return gpr_lr;
+ case gcc_pc: return gpr_pc;
+ case gcc_cpsr: return gpr_cpsr;
+ }
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextMach_arm::NumSupportedHardwareBreakpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many breakpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_breakpoints = UINT_MAX
+ if (g_num_supported_hw_breakpoints == UINT_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ // Read the DBGDIDR to get the number of available hardware breakpoints
+ // However, in some of our current armv7 processors, hardware
+ // breakpoints/watchpoints were not properly connected. So detect those
+ // cases using a field in a sysctl. For now we are using "hw.cpusubtype"
+ // field to distinguish CPU architectures. This is a hack until we can
+ // get <rdar://problem/6372672> fixed, at which point we will switch to
+ // using a different sysctl string that will tell us how many BRPs
+ // are available to us directly without having to read DBGDIDR.
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ uint32_t numBRPs = bits(register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (numBRPs > 0)
+ numBRPs++;
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, numBRPs);
+
+ if (numBRPs > 0)
+ {
+ uint32_t cpu_subtype;
+ size_t len;
+ len = sizeof(cpusubtype);
+ // TODO: remove this hack and change to using hw.optional.xx when implmented
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype);
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7)
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "Hardware breakpoints disabled for armv7 (rdar://problem/6372672)");
+ else
+ g_num_supported_hw_breakpoints = numBRPs;
+ }
+ }
+
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t
+RegisterContextMach_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ kern_return_t kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
+ uint32_t i;
+ for (i=0; i<num_hw_breakpoints; ++i)
+ {
+ if ((dbg.bcr[i] & BCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_breakpoints)
+ {
+ // Make sure bits 1:0 are clear in our address
+ dbg.bvr[i] = addr & ~((lldb::addr_t)3);
+
+ if (size == 2 || addr & 2)
+ {
+ uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1;
+
+ // We have a thumb breakpoint
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ byte_addr_select | // Set the correct byte address select so we only trigger on the correct opcode
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
+ addr,
+ size,
+ i,
+ i,
+ dbg.bvr[i],
+ dbg.bcr[i]);
+ }
+ else if (size == 4)
+ {
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
+ addr,
+ size,
+ i,
+ i,
+ dbg.bvr[i],
+ dbg.bcr[i]);
+ }
+
+ kret = WriteDBG();
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+ }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextMach_arm::ClearHardwareBreakpoint (uint32_t hw_index)
+{
+ kern_return_t kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.bcr[hw_index] = 0;
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
+ hw_index,
+ hw_index,
+ dbg.bvr[hw_index],
+ hw_index,
+ dbg.bcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextMach_arm::NumSupportedHardwareWatchpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT_MAX;
+ if (g_num_supported_hw_watchpoints == UINT_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+ // Read the DBGDIDR to get the number of available hardware breakpoints
+ // However, in some of our current armv7 processors, hardware
+ // breakpoints/watchpoints were not properly connected. So detect those
+ // cases using a field in a sysctl. For now we are using "hw.cpusubtype"
+ // field to distinguish CPU architectures. This is a hack until we can
+ // get <rdar://problem/6372672> fixed, at which point we will switch to
+ // using a different sysctl string that will tell us how many WRPs
+ // are available to us directly without having to read DBGDIDR.
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ uint32_t numWRPs = bits(register_DBGDIDR, 31, 28) + 1;
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, numWRPs);
+
+ if (numWRPs > 0)
+ {
+ uint32_t cpusubtype;
+ size_t len;
+ len = sizeof(cpusubtype);
+ // TODO: remove this hack and change to using hw.optional.xx when implmented
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype);
+
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7)
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "Hardware watchpoints disabled for armv7 (rdar://problem/6372672)");
+ else
+ g_num_supported_hw_watchpoints = numWRPs;
+ }
+ }
+
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextMach_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
+
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (read == false && write == false)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (size > 4)
+ return LLDB_INVALID_INDEX32;
+
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ kern_return_t kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i=0; i<num_hw_watchpoints; ++i)
+ {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextMach_arm::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ kern_return_t kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.wcr[hw_index] = 0;
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+ hw_index,
+ hw_index,
+ dbg.wvr[hw_index],
+ hw_index,
+ dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.h b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.h
new file mode 100644
index 0000000..37821cd
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.h
@@ -0,0 +1,302 @@
+//===-- RegisterContextMach_arm.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_RegisterContextMach_arm_h_
+#define liblldb_RegisterContextMach_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+// BCR address match type
+#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21))
+#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21))
+#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21))
+#define BCR_M_RESERVED ((uint32_t)(3u << 21))
+
+// Link a BVR/BCR or WVR/WCR pair to another
+#define E_ENABLE_LINKING ((uint32_t)(1u << 20))
+
+// Byte Address Select
+#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5))
+#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6))
+#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7))
+#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8))
+#define BAS_IMVA_0_1 ((uint32_t)(3u << 5))
+#define BAS_IMVA_2_3 ((uint32_t)(3u << 7))
+#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5))
+
+// Break only in priveleged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define BCR_ENABLE ((uint32_t)(1u))
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextMach_arm : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextMach_arm(lldb_private::Thread &thread, lldb_private::StackFrame *frame);
+
+ virtual
+ ~RegisterContextMach_arm();
+
+ 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 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 = 0);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[16];
+ } floats;
+ uint32_t fpscr;
+ };
+
+// struct NeonReg
+// {
+// uint8_t bytes[16];
+// };
+//
+// struct VFPv3
+// {
+// union {
+// uint32_t s[32];
+// uint64_t d[32];
+// NeonReg q[16];
+// } v3;
+// uint32_t fpscr;
+// };
+
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ static void
+ LogDBGRegisters (lldb_private::Log *log, const DBG& dbg);
+
+protected:
+
+ typedef enum
+ {
+ GPRRegSet = 1,
+ FPURegSet = 2,
+ EXCRegSet = 3,
+ DBGRegSet = 4,
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t),
+ DBGWordCount = sizeof(DBG)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+ kern_return_t dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ kern_return_t
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ case DBGRegSet: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == KERN_SUCCESS;
+ }
+
+ kern_return_t
+ ReadGPR (bool force);
+
+ kern_return_t
+ ReadFPU (bool force);
+
+ kern_return_t
+ ReadEXC (bool force);
+
+ kern_return_t
+ ReadDBG (bool force);
+
+ kern_return_t
+ WriteGPR ();
+
+ kern_return_t
+ WriteFPU ();
+
+ kern_return_t
+ WriteEXC ();
+
+ kern_return_t
+ WriteDBG ();
+
+ kern_return_t
+ ReadRegisterSet (uint32_t set, bool force);
+
+ kern_return_t
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextMach_arm_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.cpp b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.cpp
new file mode 100644
index 0000000..daa4f0d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.cpp
@@ -0,0 +1,1202 @@
+//===-- RegisterContextMach_i386.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
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Scalar.h"
+
+// Project includes
+#include "RegisterContextMach_i386.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_eax = 0,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48
+};
+
+RegisterContextMach_i386::RegisterContextMach_i386 (Thread &thread, StackFrame *frame) :
+ RegisterContext(thread, frame),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextMach_i386::~RegisterContextMach_i386()
+{
+}
+
+
+
+#define GPR_OFFSET(reg) (offsetof (RegisterContextMach_i386::GPR, reg))
+#define FPU_OFFSET(reg) (offsetof (RegisterContextMach_i386::FPU, reg) + sizeof (RegisterContextMach_i386::GPR))
+#define EXC_OFFSET(reg) (offsetof (RegisterContextMach_i386::EXC, reg) + sizeof (RegisterContextMach_i386::GPR) + sizeof (RegisterContextMach_i386::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextMach_i386::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex, gpr_##reg
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextMach_i386::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex, fpu_##reg
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextMach_i386::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, fpu_##reg##i, { LLDB_INVALID_REGNUM, dwarf_##reg##i, LLDB_INVALID_REGNUM, gdb_##reg##i }
+
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextMach_i386::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex, exc_##reg
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextMach_i386::GPR) + sizeof (RegisterContextMach_i386::FPU) + sizeof (RegisterContextMach_i386::EXC))
+
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC REG KIND NUM DWARF REG KIND NUM GENERIC REG KIND NUM GDB REG KIND NUM
+// =============================== ======================= =================== ========================== ==========================
+ { DEFINE_GPR(eax , NULL) , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax }},
+ { DEFINE_GPR(ebx , NULL) , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx }},
+ { DEFINE_GPR(ecx , NULL) , { gcc_ecx , dwarf_ecx , LLDB_INVALID_REGNUM , gdb_ecx }},
+ { DEFINE_GPR(edx , NULL) , { gcc_edx , dwarf_edx , LLDB_INVALID_REGNUM , gdb_edx }},
+ { DEFINE_GPR(edi , NULL) , { gcc_edi , dwarf_edi , LLDB_INVALID_REGNUM , gdb_edi }},
+ { DEFINE_GPR(esi , NULL) , { gcc_esi , dwarf_esi , LLDB_INVALID_REGNUM , gdb_esi }},
+ { DEFINE_GPR(ebp , "fp") , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp }},
+ { DEFINE_GPR(esp , "sp") , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp }},
+ { DEFINE_GPR(ss , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ss }},
+ { DEFINE_GPR(eflags , "flags") , { gcc_eflags , dwarf_eflags , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags }},
+ { DEFINE_GPR(eip , "pc") , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip }},
+ { DEFINE_GPR(cs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs }},
+ { DEFINE_GPR(ds , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds }},
+ { DEFINE_GPR(es , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_es }},
+ { DEFINE_GPR(fs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fs }},
+ { DEFINE_GPR(gs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gs }},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fcw }},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fsw }},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ftw }},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fop }},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ip }},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs }},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_dp }},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds }},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_mxcsr }},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextMach_i386::Invalidate ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextMach_i386::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextMach_i386::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextMach_i386::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextMach_i386::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextMach_i386::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextMach_i386::GetRegisterSet (uint32_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextMach_i386::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+
+void
+RegisterContextMach_i386::LogGPR(Log *log, const char *title)
+{
+ if (log)
+ {
+ if (title)
+ log->Printf ("%s", title);
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_eax + i;
+ log->Printf("%12s = 0x%8.8x", g_register_infos[reg].name, (&gpr.eax)[reg]);
+ }
+ }
+}
+
+
+
+kern_return_t
+RegisterContextMach_i386::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = GPRWordCount;
+ SetError(set, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&gpr, &count));
+ LogGPR (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD), "RegisterContextMach_i386::ReadGPR()");
+ }
+ return GetError(set, Read);
+}
+
+kern_return_t
+RegisterContextMach_i386::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = FPUWordCount;
+ SetError(set, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&fpu, &count));
+ }
+ return GetError(set, Read);
+}
+
+kern_return_t
+RegisterContextMach_i386::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = EXCWordCount;
+ SetError(set, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&exc, &count));
+ }
+ return GetError(set, Read);
+}
+
+kern_return_t
+RegisterContextMach_i386::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&gpr, GPRWordCount));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+kern_return_t
+RegisterContextMach_i386::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&fpu, FPUWordCount));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+kern_return_t
+RegisterContextMach_i386::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&exc, EXCWordCount));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+kern_return_t
+RegisterContextMach_i386::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+RegisterContextMach_i386::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+bool
+RegisterContextMach_i386::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ int set = RegisterContextMach_i386::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.eax)[reg - gpr_eax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these
+ // registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes, 16);
+ return false;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextMach_i386::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.eax)[reg - gpr_eax] = value.UInt(0);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.UInt(0);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.UInt(0);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.UInt(0);
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.UInt(0);
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.UInt(0);
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.UInt(0);
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.UInt(0);
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.UInt(0);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.UInt(0);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.UInt(0);
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, reg_value.value.vector.uint8, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, reg_value.value.vector.uint8, 16);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.UInt(0);
+ break;
+
+ case exc_err:
+ exc.err = value.UInt(0);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.UInt(0);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_i386::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ int set = RegisterContextMach_i386::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ data.SetData(&gpr.eax + reg - gpr_eax, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fcw:
+ data.SetData(&fpu.fcw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fsw:
+ data.SetData(&fpu.fsw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ftw:
+ data.SetData(&fpu.ftw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fop:
+ data.SetData(&fpu.fop, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ip:
+ data.SetData(&fpu.ip, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_cs:
+ data.SetData(&fpu.cs, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_dp:
+ data.SetData(&fpu.dp, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ds:
+ data.SetData(&fpu.ds, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsr:
+ data.SetData(&fpu.mxcsr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsrmask:
+ data.SetData(&fpu.mxcsrmask, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ data.SetData(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ data.SetData(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_trapno:
+ data.SetData(&exc.trapno, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_err:
+ data.SetData(&exc.err, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_faultvaddr:
+ data.SetData(&exc.faultvaddr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool
+RegisterContextMach_i386::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL && data.ValidOffsetForDataOfSize(data_offset, reg_info->byte_size))
+ return false;
+
+ uint32_t offset = data_offset;
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.eax)[reg - gpr_eax] = data.GetU32 (&offset);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = data.GetU16(&offset);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = data.GetU16(&offset);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = data.GetU8(&offset);
+ break;
+
+ case fpu_fop:
+ fpu.fop = data.GetU16(&offset);
+ break;
+
+ case fpu_ip:
+ fpu.ip = data.GetU32(&offset);
+ break;
+
+ case fpu_cs:
+ fpu.cs = data.GetU16(&offset);
+ break;
+
+ case fpu_dp:
+ fpu.dp = data.GetU32(&offset);
+ break;
+
+ case fpu_ds:
+ fpu.ds = data.GetU16(&offset);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = data.GetU32(&offset);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = data.GetU32(&offset);
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = data.GetU32 (&offset);
+ break;
+
+ case exc_err:
+ exc.err = data.GetU32 (&offset);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = data.GetU32 (&offset);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_i386::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextMach_i386::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextMach_i386::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_eflags: return gpr_eflags;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fctrl : return fpu_fctrl;
+ case gdb_fstat : return fpu_fstat;
+ case gdb_ftag : return fpu_ftag;
+ case gdb_fiseg : return fpu_fiseg;
+ case gdb_fioff : return fpu_fioff;
+ case gdb_foseg : return fpu_foseg;
+ case gdb_fooff : return fpu_fooff;
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+RegisterContextMach_i386::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(false) != KERN_SUCCESS)
+ return false;
+
+ const uint32_t trace_bit = 0x100u;
+ if (enable)
+ {
+ // If the trace bit is already set, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ return true;
+ else
+ gpr.eflags |= trace_bit;
+ }
+ else
+ {
+ // If the trace bit is already cleared, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ gpr.eflags &= ~trace_bit;
+ else
+ return true;
+ }
+
+ return WriteGPR() == KERN_SUCCESS;
+}
+
+
+
diff --git a/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.h b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.h
new file mode 100644
index 0000000..5801867
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.h
@@ -0,0 +1,256 @@
+//===-- RegisterContextMach_i386.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_RegisterContextMach_i386_h_
+#define liblldb_RegisterContextMach_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextMach_i386 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextMach_i386(lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame);
+
+ virtual
+ ~RegisterContextMach_i386();
+
+ 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 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 = 0);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftw;
+ uint8_t pad1;
+ uint16_t fop;
+ uint32_t ip;
+ uint16_t cs;
+ uint16_t pad2;
+ uint32_t dp;
+ uint16_t ds;
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint8_t pad4[14*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1,
+ FPURegSet = 2,
+ EXCRegSet = 3
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ kern_return_t
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == KERN_SUCCESS;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *title);
+
+ kern_return_t
+ ReadGPR (bool force);
+
+ kern_return_t
+ ReadFPU (bool force);
+
+ kern_return_t
+ ReadEXC (bool force);
+
+ kern_return_t
+ WriteGPR ();
+
+ kern_return_t
+ WriteFPU ();
+
+ kern_return_t
+ WriteEXC ();
+
+ kern_return_t
+ ReadRegisterSet (uint32_t set, bool force);
+
+ kern_return_t
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextMach_i386_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp
new file mode 100644
index 0000000..a7ed32e
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,1328 @@
+//===-- RegisterContextMach_x86_64.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
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Scalar.h"
+
+// Project includes
+#include "RegisterContextMach_x86_64.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_rax = 0,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp,
+};
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7,
+
+};
+
+enum gdb_regnums
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fctrl = 32, gdb_fpu_fcw = gdb_fpu_fctrl,
+ gdb_fpu_fstat = 33, gdb_fpu_fsw = gdb_fpu_fstat,
+ gdb_fpu_ftag = 34, gdb_fpu_ftw = gdb_fpu_ftag,
+ gdb_fpu_fiseg = 35, gdb_fpu_cs = gdb_fpu_fiseg,
+ gdb_fpu_fioff = 36, gdb_fpu_ip = gdb_fpu_fioff,
+ gdb_fpu_foseg = 37, gdb_fpu_ds = gdb_fpu_foseg,
+ gdb_fpu_fooff = 38, gdb_fpu_dp = gdb_fpu_fooff,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56,
+};
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64 (Thread &thread, StackFrame *frame) :
+ RegisterContext (thread, frame),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
+{
+}
+
+#define GPR_OFFSET(reg) (offsetof (RegisterContextMach_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) (offsetof (RegisterContextMach_x86_64::FPU, reg) + sizeof (RegisterContextMach_x86_64::GPR))
+#define EXC_OFFSET(reg) (offsetof (RegisterContextMach_x86_64::EXC, reg) + sizeof (RegisterContextMach_x86_64::GPR) + sizeof (RegisterContextMach_x86_64::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextMach_x86_64::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex, gpr_##reg
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextMach_x86_64::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex, fpu_##reg
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextMach_x86_64::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, fpu_##reg##i, { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, gdb_fpu_##reg##i }
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextMach_x86_64::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex, exc_##reg
+
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextMach_x86_64::GPR) + sizeof (RegisterContextMach_x86_64::FPU) + sizeof (RegisterContextMach_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC REG KIND NUM DWARF REG KIND NUM GENERIC REG KIND NUM GDB REG KIND NUM
+// =============================== ======================= =================== ========================== ==========================
+ { DEFINE_GPR (rax , NULL) , { gcc_dwarf_gpr_rax , gcc_dwarf_gpr_rax , LLDB_INVALID_REGNUM , gdb_gpr_rax }},
+ { DEFINE_GPR (rbx , NULL) , { gcc_dwarf_gpr_rbx , gcc_dwarf_gpr_rbx , LLDB_INVALID_REGNUM , gdb_gpr_rbx }},
+ { DEFINE_GPR (rcx , NULL) , { gcc_dwarf_gpr_rcx , gcc_dwarf_gpr_rcx , LLDB_INVALID_REGNUM , gdb_gpr_rcx }},
+ { DEFINE_GPR (rdx , NULL) , { gcc_dwarf_gpr_rdx , gcc_dwarf_gpr_rdx , LLDB_INVALID_REGNUM , gdb_gpr_rdx }},
+ { DEFINE_GPR (rdi , NULL) , { gcc_dwarf_gpr_rdi , gcc_dwarf_gpr_rdi , LLDB_INVALID_REGNUM , gdb_gpr_rdi }},
+ { DEFINE_GPR (rsi , NULL) , { gcc_dwarf_gpr_rsi , gcc_dwarf_gpr_rsi , LLDB_INVALID_REGNUM , gdb_gpr_rsi }},
+ { DEFINE_GPR (rbp , "fp") , { gcc_dwarf_gpr_rbp , gcc_dwarf_gpr_rbp , LLDB_REGNUM_GENERIC_FP , gdb_gpr_rbp }},
+ { DEFINE_GPR (rsp , "sp") , { gcc_dwarf_gpr_rsp , gcc_dwarf_gpr_rsp , LLDB_REGNUM_GENERIC_SP , gdb_gpr_rsp }},
+ { DEFINE_GPR (r8 , NULL) , { gcc_dwarf_gpr_r8 , gcc_dwarf_gpr_r8 , LLDB_INVALID_REGNUM , gdb_gpr_r8 }},
+ { DEFINE_GPR (r9 , NULL) , { gcc_dwarf_gpr_r9 , gcc_dwarf_gpr_r9 , LLDB_INVALID_REGNUM , gdb_gpr_r9 }},
+ { DEFINE_GPR (r10 , NULL) , { gcc_dwarf_gpr_r10 , gcc_dwarf_gpr_r10 , LLDB_INVALID_REGNUM , gdb_gpr_r10 }},
+ { DEFINE_GPR (r11 , NULL) , { gcc_dwarf_gpr_r11 , gcc_dwarf_gpr_r11 , LLDB_INVALID_REGNUM , gdb_gpr_r11 }},
+ { DEFINE_GPR (r12 , NULL) , { gcc_dwarf_gpr_r12 , gcc_dwarf_gpr_r12 , LLDB_INVALID_REGNUM , gdb_gpr_r12 }},
+ { DEFINE_GPR (r13 , NULL) , { gcc_dwarf_gpr_r13 , gcc_dwarf_gpr_r13 , LLDB_INVALID_REGNUM , gdb_gpr_r13 }},
+ { DEFINE_GPR (r14 , NULL) , { gcc_dwarf_gpr_r14 , gcc_dwarf_gpr_r14 , LLDB_INVALID_REGNUM , gdb_gpr_r14 }},
+ { DEFINE_GPR (r15 , NULL) , { gcc_dwarf_gpr_r15 , gcc_dwarf_gpr_r15 , LLDB_INVALID_REGNUM , gdb_gpr_r15 }},
+ { DEFINE_GPR (rip , "pc") , { gcc_dwarf_gpr_rip , gcc_dwarf_gpr_rip , LLDB_REGNUM_GENERIC_PC , gdb_gpr_rip }},
+ { DEFINE_GPR (rflags, "flags") , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , gdb_gpr_rflags}},
+ { DEFINE_GPR (cs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gpr_cs }},
+ { DEFINE_GPR (fs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gpr_fs }},
+ { DEFINE_GPR (gs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gpr_gs }},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_fcw }},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_fsw }},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_ftw }},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_fop }},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_ip }},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_cs }},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_dp }},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_ds }},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_mxcsr }},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+ { DEFINE_FPU_VECT(xmm,8) },
+ { DEFINE_FPU_VECT(xmm,9) },
+ { DEFINE_FPU_VECT(xmm,10) },
+ { DEFINE_FPU_VECT(xmm,11) },
+ { DEFINE_FPU_VECT(xmm,12) },
+ { DEFINE_FPU_VECT(xmm,13) },
+ { DEFINE_FPU_VECT(xmm,14) },
+ { DEFINE_FPU_VECT(xmm,15) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+
+void
+RegisterContextMach_x86_64::Invalidate ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextMach_x86_64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+
+const RegisterInfo *
+RegisterContextMach_x86_64::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+
+size_t
+RegisterContextMach_x86_64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextMach_x86_64::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+
+static uint32_t g_gpr_regnums[] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs
+};
+
+static uint32_t g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextMach_x86_64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextMach_x86_64::GetRegisterSet (uint32_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+int
+RegisterContextMach_x86_64::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+void
+RegisterContextMach_x86_64::LogGPR(Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ if (format)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_rax + i;
+ log->Printf("%12s = 0x%16.16llx", g_register_infos[reg].name, (&gpr.rax)[reg]);
+ }
+ }
+}
+
+kern_return_t
+RegisterContextMach_x86_64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = GPRWordCount;
+ SetError(GPRRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&gpr, &count));
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log)
+ LogGPR (log, "RegisterContextMach_x86_64::ReadGPR(thread = 0x%4.4x)", GetThreadID());
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = FPUWordCount;
+ SetError(FPURegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&fpu, &count));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = EXCWordCount;
+ SetError(EXCRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&exc, &count));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log)
+ LogGPR (log, "RegisterContextMach_x86_64::WriteGPR (thread = 0x%4.4x)", GetThreadID());
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&gpr, GPRWordCount));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&fpu, FPUWordCount));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&exc, EXCWordCount));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::ReadRegisterSet(uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR (force);
+ case FPURegSet: return ReadFPU (force);
+ case EXCRegSet: return ReadEXC (force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+RegisterContextMach_x86_64::WriteRegisterSet(uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR ();
+ case FPURegSet: return WriteFPU ();
+ case EXCRegSet: return WriteEXC ();
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+
+bool
+RegisterContextMach_x86_64::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.rax)[reg - gpr_rax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these
+ // registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes, 16);
+ return false;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextMach_x86_64::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.rax)[reg - gpr_rax] = value.ULongLong(0);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.UInt(0);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.UInt(0);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.UInt(0);
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.UInt(0);
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.UInt(0);
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.UInt(0);
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.UInt(0);
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.UInt(0);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.UInt(0);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.UInt(0);
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, reg_value.value.vector.uint8, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, reg_value.value.vector.uint8, 16);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.UInt(0);
+ break;
+
+ case exc_err:
+ exc.err = value.UInt(0);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.UInt(0);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_x86_64::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ data.SetData(&gpr.rax + reg - gpr_rax, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fcw:
+ data.SetData(&fpu.fcw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fsw:
+ data.SetData(&fpu.fsw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ftw:
+ data.SetData(&fpu.ftw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fop:
+ data.SetData(&fpu.fop, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ip:
+ data.SetData(&fpu.ip, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_cs:
+ data.SetData(&fpu.cs, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_dp:
+ data.SetData(&fpu.dp, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ds:
+ data.SetData(&fpu.ds, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsr:
+ data.SetData(&fpu.mxcsr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsrmask:
+ data.SetData(&fpu.mxcsrmask, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ data.SetData(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ data.SetData(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_trapno:
+ data.SetData(&exc.trapno, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_err:
+ data.SetData(&exc.err, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_faultvaddr:
+ data.SetData(&exc.faultvaddr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool
+RegisterContextMach_x86_64::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL && data.ValidOffsetForDataOfSize(data_offset, reg_info->byte_size))
+ return false;
+
+ uint32_t offset = data_offset;
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.rax)[reg - gpr_rax] = data.GetU32 (&offset);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = data.GetU16(&offset);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = data.GetU16(&offset);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = data.GetU8(&offset);
+ break;
+
+ case fpu_fop:
+ fpu.fop = data.GetU16(&offset);
+ break;
+
+ case fpu_ip:
+ fpu.ip = data.GetU32(&offset);
+ break;
+
+ case fpu_cs:
+ fpu.cs = data.GetU16(&offset);
+ break;
+
+ case fpu_dp:
+ fpu.dp = data.GetU32(&offset);
+ break;
+
+ case fpu_ds:
+ fpu.ds = data.GetU16(&offset);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = data.GetU32(&offset);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = data.GetU32(&offset);
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = data.GetU32 (&offset);
+ break;
+
+ case exc_err:
+ exc.err = data.GetU32 (&offset);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = data.GetU32 (&offset);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextMach_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextMach_x86_64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_gs; // HACK: For now for "ss", just copy what is in "gs"
+ case gdb_gpr_ds : return gpr_gs; // HACK: For now for "ds", just copy what is in "gs"
+ case gdb_gpr_es : return gpr_gs; // HACK: For now for "es", just copy what is in "gs"
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fctrl : return fpu_fctrl;
+ case gdb_fpu_fstat : return fpu_fstat;
+ case gdb_fpu_ftag : return fpu_ftag;
+ case gdb_fpu_fiseg : return fpu_fiseg;
+ case gdb_fpu_fioff : return fpu_fioff;
+ case gdb_fpu_foseg : return fpu_foseg;
+ case gdb_fpu_fooff : return fpu_fooff;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextMach_x86_64::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(true) != KERN_SUCCESS)
+ return false;
+
+ const uint64_t trace_bit = 0x100ull;
+ if (enable)
+ {
+
+ if (gpr.rflags & trace_bit)
+ return true; // trace bit is already set, there is nothing to do
+ else
+ gpr.rflags |= trace_bit;
+ }
+ else
+ {
+ if (gpr.rflags & trace_bit)
+ gpr.rflags &= ~trace_bit;
+ else
+ return true; // trace bit is clear, there is nothing to do
+ }
+
+ return WriteGPR() == KERN_SUCCESS;
+}
+
diff --git a/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h
new file mode 100644
index 0000000..4f33bbd
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h
@@ -0,0 +1,261 @@
+//===-- RegisterContextMach_x86_64.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_RegisterContextMach_x86_64_h_
+#define liblldb_RegisterContextMach_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextMach_x86_64 : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextMach_x86_64 (lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame);
+
+ virtual
+ ~RegisterContextMach_x86_64();
+
+ 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 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 = 0);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw; // "fctrl"
+ uint16_t fsw; // "fstat"
+ uint8_t ftw; // "ftag"
+ uint8_t pad1;
+ uint16_t fop; // "fop"
+ uint32_t ip; // "fioff"
+ uint16_t cs; // "fiseg"
+ uint16_t pad2;
+ uint32_t dp; // "fooff"
+ uint16_t ds; // "foseg"
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint8_t pad4[6*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint64_t faultvaddr;
+ };
+
+protected:
+
+ typedef enum
+ {
+ GPRRegSet = 4,
+ FPURegSet = 5,
+ EXCRegSet = 6
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ kern_return_t
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == KERN_SUCCESS;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *format, ...);
+
+ kern_return_t
+ ReadGPR (bool force);
+
+ kern_return_t
+ ReadFPU (bool force);
+
+ kern_return_t
+ ReadEXC (bool force);
+
+ kern_return_t
+ WriteGPR ();
+
+ kern_return_t
+ WriteFPU ();
+
+ kern_return_t
+ WriteEXC ();
+
+ kern_return_t
+ ReadRegisterSet (uint32_t set, bool force);
+
+ kern_return_t
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb::RegisterInfo *
+ GetRegisterInfos ();
+
+};
+
+#endif // liblldb_RegisterContextMach_x86_64_h_
diff --git a/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp b/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp
new file mode 100644
index 0000000..46d84a8
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp
@@ -0,0 +1,769 @@
+//===-- ThreadMacOSX.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadMacOSX.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+#include "MachThreadContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Breakpoint/WatchpointLocation.h"
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadMacOSX::ThreadMacOSX (ProcessMacOSX &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_fp_pc_pairs(),
+ m_basic_info(),
+ m_suspend_count(0),
+ m_stop_exception(),
+ m_context()
+{
+ ProcessMacOSX::CreateArchCalback create_arch_callback = process.GetArchCreateCallback();
+ assert(create_arch_callback != NULL);
+ m_context.reset(create_arch_callback(process.GetArchSpec(), *this));
+ assert(m_context.get() != NULL);
+ m_context->InitializeInstance();
+ ::bzero (&m_basic_info, sizeof (m_basic_info));
+ ::bzero (&m_ident_info, sizeof (m_ident_info));
+ ::bzero (&m_proc_threadinfo, sizeof (m_proc_threadinfo));
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD | PD_LOG_VERBOSE, "ThreadMacOSX::ThreadMacOSX ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID());
+}
+
+ThreadMacOSX::~ThreadMacOSX ()
+{
+}
+
+#if defined (__i386__) || defined (__x86_64__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_I386_BPT
+ #define MACH_TRAP_DATA_0 EXC_I386_SGL
+#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_PPC_BREAKPOINT
+
+#elif defined (__arm__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_ARM_BREAKPOINT
+#endif
+
+
+bool
+ThreadMacOSX::GetRawStopReason (Thread::StopInfo *stop_info )
+{
+ stop_info->SetThread(this);
+
+ bool success = GetStopException().GetStopInfo(stop_info);
+
+
+#if defined (MACH_SOFTWARE_BREAKPOINT_DATA_0) || defined (MACH_TRAP_DATA_0)
+ if (stop_info->GetStopReason() == eStopReasonException)
+ {
+ if (stop_info->GetExceptionType() == EXC_BREAKPOINT && stop_info->GetExceptionDataCount() == 2)
+ {
+ const lldb::addr_t data_0 = stop_info->GetExceptionDataAtIndex(0);
+#if defined (MACH_SOFTWARE_BREAKPOINT_DATA_0)
+ if (data_0 == MACH_SOFTWARE_BREAKPOINT_DATA_0)
+ {
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ lldb::user_id_t break_id = m_process.GetBreakpointSiteList().FindIDByAddress(pc);
+ if (break_id != LLDB_INVALID_BREAK_ID)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithBreakpointSiteID (break_id);
+ return success;
+ }
+ }
+#endif
+#if defined (MACH_TRAP_DATA_0)
+ if (data_0 == MACH_TRAP_DATA_0)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonToTrace ();
+ return success;
+ }
+#endif
+ }
+ }
+#endif
+
+ if (stop_info->GetStopReason() == eStopReasonException)
+ {
+ if (stop_info->GetExceptionType() == EXC_SOFTWARE &&
+ stop_info->GetExceptionDataCount() == 2 &&
+ stop_info->GetExceptionDataAtIndex(0) == EXC_SOFT_SIGNAL)
+ {
+ int signo = stop_info->GetExceptionDataAtIndex(1);
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithSignal (signo);
+ }
+ }
+ else
+ {
+ stop_info->SetStopReasonToNone();
+ }
+
+ return success;
+}
+
+const char *
+ThreadMacOSX::GetInfo ()
+{
+ return GetBasicInfoAsString();
+}
+
+bool
+ThreadMacOSX::GetIdentifierInfo ()
+{
+#ifdef THREAD_IDENTIFIER_INFO_COUNT
+ if (m_ident_info.thread_id == 0)
+ {
+ mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+ return ::thread_info (GetID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count) == KERN_SUCCESS;
+ }
+#else
+ //m_error.SetErrorString("Thread_info doesn't support THREAD_IDENTIFIER_INFO.");
+#endif
+
+ return false;
+}
+
+const char *
+ThreadMacOSX::GetDispatchQueueName()
+{
+ if (GetIdentifierInfo ())
+ {
+ if (m_ident_info.dispatch_qaddr == 0)
+ return NULL;
+
+ uint8_t memory_buffer[8];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer), m_process.GetByteOrder(), m_process.GetAddressByteSize());
+ ModuleSP module_sp(m_process.GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib")));
+ if (module_sp.get() == NULL)
+ return NULL;
+
+ lldb::addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+ const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData);
+ if (dispatch_queue_offsets_symbol)
+ dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(&GetProcess());
+
+ if (dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ return NULL;
+
+ // Excerpt from src/queue_private.h
+ struct dispatch_queue_offsets_s
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ } dispatch_queue_offsets;
+
+ Error error;
+ if (m_process.ReadMemory (dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
+ {
+ uint32_t data_offset = 0;
+ if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
+ {
+ if (m_process.ReadMemory (m_ident_info.dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t queue_addr = data.GetAddress(&data_offset);
+ lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
+ const size_t chunk_size = 32;
+ uint32_t label_pos = 0;
+ m_dispatch_queue_name.resize(chunk_size, '\0');
+ while (1)
+ {
+ size_t bytes_read = m_process.ReadMemory (label_addr + label_pos, &m_dispatch_queue_name[label_pos], chunk_size, error);
+
+ if (bytes_read <= 0)
+ break;
+
+ if (m_dispatch_queue_name.find('\0', label_pos) != std::string::npos)
+ break;
+ label_pos += bytes_read;
+ }
+ m_dispatch_queue_name.erase(m_dispatch_queue_name.find('\0'));
+ }
+ }
+ }
+ }
+
+ if (m_dispatch_queue_name.empty())
+ return NULL;
+ return m_dispatch_queue_name.c_str();
+}
+
+const char *
+ThreadMacOSX::GetName ()
+{
+ if (GetIdentifierInfo ())
+ ::proc_pidinfo (m_process.GetID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
+
+ // No thread name, lets return the queue name instead
+ if (m_proc_threadinfo.pth_name[0] == '\0')
+ return GetDispatchQueueName();
+
+ // Return the thread name if there was one
+ if (m_proc_threadinfo.pth_name[0])
+ return m_proc_threadinfo.pth_name;
+ return NULL;
+}
+
+bool
+ThreadMacOSX::WillResume (StateType resume_state)
+{
+ ThreadWillResume(resume_state);
+ Thread::WillResume(resume_state);
+ return true;
+}
+
+void
+ThreadMacOSX::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context
+ GetRegisterContext()->Invalidate();
+
+ m_context->RefreshStateAfterStop();
+
+ // We may have suspended this thread so the primary thread could step
+ // without worrying about race conditions, so lets restore our suspend
+ // count.
+ RestoreSuspendCount();
+
+ // Update the basic information for a thread for suspend count reasons.
+ ThreadMacOSX::GetBasicInfo(GetID(), &m_basic_info);
+ m_suspend_count = m_basic_info.suspend_count;
+ m_basic_info_string.clear();
+}
+
+uint32_t
+ThreadMacOSX::GetStackFrameCount()
+{
+ if (m_fp_pc_pairs.empty())
+ GetStackFrameData(m_fp_pc_pairs);
+ return m_fp_pc_pairs.size();
+}
+
+// Make sure that GetStackFrameAtIndex() does NOT call GetStackFrameCount() when
+// getting the stack frame at index zero! This way GetStackFrameCount() (via
+// GetStackFRameData()) can call this function to get the first frame in order
+// to provide the first frame to a lower call for efficiency sake (avoid
+// redundant lookups in the frame symbol context).
+lldb::StackFrameSP
+ThreadMacOSX::GetStackFrameAtIndex (uint32_t idx)
+{
+ StackFrameSP frame_sp(m_frames.GetFrameAtIndex(idx));
+
+ if (frame_sp)
+ return frame_sp;
+
+ // Don't try and fetch a frame while process is running
+ // Calling IsRunning isn't right here, because IsRunning reads the Public
+ // state but we need to be able to read the stack frames in the ShouldStop
+ // methods, which happen before the Public state has been updated.
+// if (m_process.IsRunning())
+// return frame_sp;
+
+ // Special case the first frame (idx == 0) so that we don't need to
+ // know how many stack frames there are to get it. If we need any other
+ // frames, then we do need to know if "idx" is a valid index.
+ if (idx == 0)
+ {
+ // If this is the first frame, we want to share the thread register
+ // context with the stack frame at index zero.
+ GetRegisterContext();
+ assert (m_reg_context_sp.get());
+ frame_sp.reset (new StackFrame (idx, *this, m_reg_context_sp, m_reg_context_sp->GetFP(), m_reg_context_sp->GetPC()));
+ }
+ else if (idx < GetStackFrameCount())
+ {
+ assert (idx < m_fp_pc_pairs.size());
+ frame_sp.reset (new StackFrame (idx, *this, m_fp_pc_pairs[idx].first, m_fp_pc_pairs[idx].second));
+ }
+ m_frames.SetFrameAtIndex(idx, frame_sp);
+ return frame_sp;
+}
+
+void
+ThreadMacOSX::ClearStackFrames ()
+{
+ m_fp_pc_pairs.clear();
+ Thread::ClearStackFrames();
+}
+
+
+
+int32_t
+ThreadMacOSX::Suspend()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid))
+ {
+ Error err(::thread_suspend (tid), eErrorTypeMachKernel);
+ if (err.Success())
+ m_suspend_count++;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_suspend (%4.4x)", tid);
+ }
+ return GetSuspendCount();
+}
+
+int32_t
+ThreadMacOSX::Resume()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ()", __FUNCTION__);
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid))
+ {
+ while (m_suspend_count > 0)
+ {
+ Error err(::thread_resume (tid), eErrorTypeMachKernel);
+ if (err.Success())
+ m_suspend_count--;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_resume (%4.4x)", tid);
+ }
+ }
+ return GetSuspendCount();
+}
+
+bool
+ThreadMacOSX::RestoreSuspendCount()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
+ Error err;
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid) == false)
+ return false;
+ else if (m_suspend_count > m_basic_info.suspend_count)
+ {
+ while (m_suspend_count > m_basic_info.suspend_count)
+ {
+ err = ::thread_resume (tid);
+ if (err.Success())
+ --m_suspend_count;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_resume (%4.4x)", tid);
+ }
+ }
+ else if (m_suspend_count < m_basic_info.suspend_count)
+ {
+ while (m_suspend_count < m_basic_info.suspend_count)
+ {
+ err = ::thread_suspend (tid);
+ if (err.Success())
+ --m_suspend_count;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_suspend (%4.4x)", tid);
+ }
+ }
+ return m_suspend_count == m_basic_info.suspend_count;
+}
+
+
+const char *
+ThreadMacOSX::GetBasicInfoAsString ()
+{
+ if (m_basic_info_string.empty())
+ {
+ StreamString sstr;
+ struct thread_basic_info basicInfo;
+
+ lldb::tid_t tid = GetID ();
+ if (GetBasicInfo(tid, &basicInfo))
+ {
+// char run_state_str[32];
+// size_t run_state_str_size = sizeof(run_state_str);
+// switch (basicInfo.run_state)
+// {
+// case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break;
+// case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break;
+// case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break;
+// case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
+// case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break;
+// default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ???
+// }
+ float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ sstr.Printf("Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
+ InferiorThreadID(),
+ user,
+ system,
+ basicInfo.cpu_usage,
+ basicInfo.sleep_time);
+ m_basic_info_string.assign (sstr.GetData(), sstr.GetSize());
+ }
+ }
+ if (m_basic_info_string.empty())
+ return NULL;
+ return m_basic_info_string.c_str();
+}
+
+
+//const uint8_t *
+//ThreadMacOSX::SoftwareBreakpointOpcode (size_t break_op_size) const
+//{
+// return m_context->SoftwareBreakpointOpcode(break_op_size);
+//}
+
+
+lldb::tid_t
+ThreadMacOSX::InferiorThreadID() const
+{
+ mach_msg_type_number_t i;
+ mach_port_name_array_t names;
+ mach_port_type_array_t types;
+ mach_msg_type_number_t ncount, tcount;
+ lldb::tid_t inferior_tid = LLDB_INVALID_THREAD_ID;
+ task_t my_task = ::mach_task_self();
+ task_t task = GetMacOSXProcess().Task().GetTaskPort();
+
+ kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
+ if (kret == KERN_SUCCESS)
+ {
+ lldb::tid_t tid = GetID ();
+
+ for (i = 0; i < ncount; i++)
+ {
+ mach_port_t my_name;
+ mach_msg_type_name_t my_type;
+
+ kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
+ if (kret == KERN_SUCCESS)
+ {
+ ::mach_port_deallocate (my_task, my_name);
+ if (my_name == tid)
+ {
+ inferior_tid = names[i];
+ break;
+ }
+ }
+ }
+ // Free up the names and types
+ ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
+ ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
+ }
+ return inferior_tid;
+}
+
+bool
+ThreadMacOSX::GetBasicInfo(lldb::tid_t thread, struct thread_basic_info *basicInfoPtr)
+{
+ if (ThreadIDIsValid(thread))
+ {
+ unsigned int info_count = THREAD_BASIC_INFO_COUNT;
+ kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
+ if (err == KERN_SUCCESS)
+ return true;
+ }
+ ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
+ return false;
+}
+
+
+bool
+ThreadMacOSX::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadMacOSX::Dump(Log *log, uint32_t index)
+{
+ const char * thread_run_state = NULL;
+
+ switch (m_basic_info.run_state)
+ {
+ case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally
+ case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped
+ case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally
+ case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait
+ case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a
+ default: thread_run_state = "???"; break;
+ }
+
+ RegisterContext *reg_context = GetRegisterContext();
+ log->Printf ("thread[%u] %4.4x (%u): pc: 0x%8.8llx sp: 0x%8.8llx breakID: %d user: %d.%06.6d system: %d.%06.6d cpu: %d policy: %d run_state: %d (%s) flags: %d suspend_count: %d (current %d) sleep_time: %d",
+ index,
+ GetID (),
+ reg_context->GetPC (LLDB_INVALID_ADDRESS),
+ reg_context->GetSP (LLDB_INVALID_ADDRESS),
+ m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds,
+ m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds,
+ m_basic_info.cpu_usage,
+ m_basic_info.policy,
+ m_basic_info.run_state,
+ thread_run_state,
+ m_basic_info.flags,
+ m_basic_info.suspend_count, m_suspend_count,
+ m_basic_info.sleep_time);
+ //DumpRegisterState(0);
+}
+
+void
+ThreadMacOSX::ThreadWillResume (StateType resume_state)
+{
+ // Update the thread state to be the state we wanted when the task resumes
+ SetState (resume_state);
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ Suspend();
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ Resume();
+ break;
+ }
+ m_context->ThreadWillResume();
+}
+
+void
+ThreadMacOSX::DidResume ()
+{
+ // TODO: cache current stack frames for next time in case we can match things up??
+ ClearStackFrames();
+ m_stop_exception.Clear();
+ Thread::DidResume();
+}
+
+bool
+ThreadMacOSX::ShouldStop(bool &step_more)
+{
+// TODO: REmove this after all is working, Process should be managing this
+// for us.
+//
+// // See if this thread is at a breakpoint?
+// lldb::user_id_t breakID = CurrentBreakpoint();
+//
+// if (LLDB_BREAK_ID_IS_VALID(breakID))
+// {
+// // This thread is sitting at a breakpoint, ask the breakpoint
+// // if we should be stopping here.
+// if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID))
+// return true;
+// else
+// {
+// // The breakpoint said we shouldn't stop, but we may have gotten
+// // a signal or the user may have requested to stop in some other
+// // way. Stop if we have a valid exception (this thread won't if
+// // another thread was the reason this process stopped) and that
+// // exception, is NOT a breakpoint exception (a common case would
+// // be a SIGINT signal).
+// if (GetStopException().IsValid() && !GetStopException().IsBreakpoint())
+// return true;
+// }
+// }
+// else
+// {
+ if (m_context->StepNotComplete())
+ {
+ step_more = true;
+ return false;
+ }
+// // The thread state is used to let us know what the thread was
+// // trying to do. ThreadMacOSX::ThreadWillResume() will set the
+// // thread state to various values depending if the thread was
+// // the current thread and if it was to be single stepped, or
+// // resumed.
+// if (GetState() == eStateRunning)
+// {
+// // If our state is running, then we should continue as we are in
+// // the process of stepping over a breakpoint.
+// return false;
+// }
+// else
+// {
+// // Stop if we have any kind of valid exception for this
+// // thread.
+// if (GetStopException().IsValid())
+// return true;
+// }
+// }
+// return false;
+ return true;
+}
+
+bool
+ThreadMacOSX::NotifyException(MachException::Data& exc)
+{
+ if (m_stop_exception.IsValid())
+ {
+ // We may have more than one exception for a thread, but we need to
+ // only remember the one that we will say is the reason we stopped.
+ // We may have been single stepping and also gotten a signal exception,
+ // so just remember the most pertinent one.
+ if (m_stop_exception.IsBreakpoint())
+ m_stop_exception = exc;
+ }
+ else
+ {
+ m_stop_exception = exc;
+ }
+// bool handled =
+ m_context->NotifyException(exc);
+// if (!handled)
+// {
+// handled = true;
+// lldb::addr_t pc = GetPC();
+// lldb::user_id_t breakID = m_process.Breakpoints().FindIDCyAddress(pc);
+// SetCurrentBreakpoint(breakID);
+// switch (exc.exc_type)
+// {
+// case EXC_BAD_ACCESS:
+// break;
+// case EXC_BAD_INSTRUCTION:
+// break;
+// case EXC_ARITHMETIC:
+// break;
+// case EXC_EMULATION:
+// break;
+// case EXC_SOFTWARE:
+// break;
+// case EXC_BREAKPOINT:
+// break;
+// case EXC_SYSCALL:
+// break;
+// case EXC_MACH_SYSCALL:
+// break;
+// case EXC_RPC_ALERT:
+// break;
+// }
+// }
+// return handled;
+ return true;
+}
+
+RegisterContext *
+ThreadMacOSX::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp.reset (CreateRegisterContextForFrame (NULL));
+ return m_reg_context_sp.get();
+}
+
+RegisterContext *
+ThreadMacOSX::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ return m_context->CreateRegisterContext (frame);
+}
+
+uint32_t
+ThreadMacOSX::SetHardwareBreakpoint (const BreakpointSite *bp)
+{
+ if (bp != NULL)
+ return GetRegisterContext()->SetHardwareBreakpoint(bp->GetLoadAddress(), bp->GetByteSize());
+ return LLDB_INVALID_INDEX32;
+}
+
+uint32_t
+ThreadMacOSX::SetHardwareWatchpoint (const WatchpointLocation *wp)
+{
+ if (wp != NULL)
+ return GetRegisterContext()->SetHardwareWatchpoint(wp->GetLoadAddress(), wp->GetByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
+ return LLDB_INVALID_INDEX32;
+}
+
+
+bool
+ThreadMacOSX::SaveFrameZeroState (RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ checkpoint.SetStackID(frame_sp->GetStackID());
+ return frame_sp->GetRegisterContext()->ReadAllRegisterValues (checkpoint.GetData());
+ }
+ return false;
+}
+
+bool
+ThreadMacOSX::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ bool ret = frame_sp->GetRegisterContext()->WriteAllRegisterValues (checkpoint.GetData());
+
+ // Clear out all stack frames as our world just changed.
+ ClearStackFrames();
+ frame_sp->GetRegisterContext()->Invalidate();
+
+ return ret;
+ }
+ return false;
+}
+
+bool
+ThreadMacOSX::ClearHardwareBreakpoint (const BreakpointSite *bp)
+{
+ if (bp != NULL && bp->IsHardware())
+ return GetRegisterContext()->ClearHardwareBreakpoint(bp->GetHardwareIndex());
+ return false;
+}
+
+bool
+ThreadMacOSX::ClearHardwareWatchpoint (const WatchpointLocation *wp)
+{
+ if (wp != NULL && wp->IsHardware())
+ return GetRegisterContext()->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ return false;
+}
+
+size_t
+ThreadMacOSX::GetStackFrameData(std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ return m_context->GetStackFrameData(frame_sp.get(), fp_pc_pairs);
+}
+
+
+//void
+//ThreadMacOSX::NotifyBreakpointChanged (const BreakpointSite *bp)
+//{
+// if (bp)
+// {
+// lldb::user_id_t breakID = bp->GetID();
+// if (bp->IsEnabled())
+// {
+// if (bp->Address() == GetPC())
+// {
+// SetCurrentBreakpoint(breakID);
+// }
+// }
+// else
+// {
+// if (CurrentBreakpoint() == breakID)
+// {
+// SetCurrentBreakpoint(LLDB_INVALID_BREAK_ID);
+// }
+// }
+// }
+//}
+//
+
+
diff --git a/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.h b/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.h
new file mode 100644
index 0000000..0039f36
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.h
@@ -0,0 +1,159 @@
+//===-- ThreadMacOSX.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_ThreadMacOSX_h_
+#define liblldb_ThreadMacOSX_h_
+
+#include <libproc.h>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "MachException.h"
+
+class ProcessMacOSX;
+class MachThreadContext;
+
+class ThreadMacOSX : public lldb_private::Thread
+{
+public:
+ ThreadMacOSX (ProcessMacOSX &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadMacOSX ();
+
+ virtual bool
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetInfo ();
+
+ virtual const char *
+ GetName ();
+
+ virtual lldb_private::RegisterContext *
+ GetRegisterContext ();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ SaveFrameZeroState (RegisterCheckpoint &checkpoint);
+
+ virtual bool
+ RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
+
+ virtual uint32_t
+ GetStackFrameCount();
+
+ virtual lldb::StackFrameSP
+ GetStackFrameAtIndex (uint32_t idx);
+
+ virtual void
+ ClearStackFrames ();
+
+ ProcessMacOSX &
+ GetMacOSXProcess ()
+ {
+ return (ProcessMacOSX &)m_process;
+ }
+
+ const ProcessMacOSX &
+ GetMacOSXProcess () const
+ {
+ return (ProcessMacOSX &)m_process;
+ }
+
+ void
+ Dump (lldb_private::Log *log, uint32_t index);
+
+ lldb::tid_t
+ InferiorThreadID () const;
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ int32_t
+ Resume ();
+
+ int32_t
+ Suspend ();
+
+ int32_t
+ GetSuspendCount () const { return m_suspend_count; }
+
+ bool
+ RestoreSuspendCount ();
+
+ uint32_t
+ SetHardwareBreakpoint (const lldb_private::BreakpointSite *bp);
+
+ uint32_t
+ SetHardwareWatchpoint (const lldb_private::WatchpointLocation *wp);
+
+ bool
+ ClearHardwareBreakpoint (const lldb_private::BreakpointSite *bp);
+
+ bool
+ ClearHardwareWatchpoint (const lldb_private::WatchpointLocation *wp);
+
+ void
+ ThreadWillResume (lldb::StateType resume_state);
+
+ virtual void
+ DidResume ();
+
+ bool
+ ShouldStop (bool &step_more);
+
+ bool
+ NotifyException (MachException::Data& exc);
+
+ const MachException::Data&
+ GetStopException () { return m_stop_exception; }
+
+ const char *
+ GetBasicInfoAsString ();
+
+ size_t
+ GetStackFrameData (std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
+
+ virtual bool
+ GetRawStopReason (lldb_private::Thread::StopInfo *stop_info);
+
+protected:
+ bool
+ GetIdentifierInfo ();
+
+ const char *
+ GetDispatchQueueName();
+
+ static bool
+ GetBasicInfo (lldb::tid_t threadID, struct thread_basic_info *basic_info);
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::vector<std::pair<lldb::addr_t, lldb::addr_t> > m_fp_pc_pairs;
+ struct thread_basic_info m_basic_info; // Basic information for a thread used to see if a thread is valid
+ std::string m_basic_info_string;// Basic thread info as a C string.
+#ifdef THREAD_IDENTIFIER_INFO_COUNT
+ thread_identifier_info_data_t m_ident_info;
+ struct proc_threadinfo m_proc_threadinfo;
+ std::string m_dispatch_queue_name;
+#endif
+ int32_t m_suspend_count; // The current suspend count
+ MachException::Data m_stop_exception; // The best exception that describes why this thread is stopped
+ std::auto_ptr<MachThreadContext> m_context; // The arch specific thread context for this thread (register state and more)
+
+};
+
+#endif // liblldb_ThreadMacOSX_h_
diff --git a/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp b/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp
new file mode 100644
index 0000000..bf6b6c2
--- /dev/null
+++ b/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, ®_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/source/Plugins/Process/Utility/LibUnwindRegisterContext.h b/source/Plugins/Process/Utility/LibUnwindRegisterContext.h
new file mode 100644
index 0000000..4e89b27
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp b/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp
new file mode 100644
index 0000000..58a7ac0
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h b/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h
new file mode 100644
index 0000000..78bd27b
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 0000000..df2f7c0
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
new file mode 100644
index 0000000..f4118c2
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/UnwindLibUnwind.cpp b/source/Plugins/Process/Utility/UnwindLibUnwind.cpp
new file mode 100644
index 0000000..1b6fa58
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/UnwindLibUnwind.h b/source/Plugins/Process/Utility/UnwindLibUnwind.h
new file mode 100644
index 0000000..d91f164
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
new file mode 100644
index 0000000..586e3d7
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
new file mode 100644
index 0000000..86ba6e7
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/include/libunwind.h b/source/Plugins/Process/Utility/libunwind/include/libunwind.h
new file mode 100644
index 0000000..63cc8ba
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h b/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h
new file mode 100644
index 0000000..bee2ad5
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/include/unwind.h b/source/Plugins/Process/Utility/libunwind/include/unwind.h
new file mode 100644
index 0000000..80b9d28
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp b/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp
new file mode 100644
index 0000000..5173dc0
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp b/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp
new file mode 100644
index 0000000..d19d7ae
--- /dev/null
+++ b/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 ®isters,
+ 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/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp b/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
new file mode 100644
index 0000000..1e695d5
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp b/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp
new file mode 100644
index 0000000..b34f93f
--- /dev/null
+++ b/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 (®no)) {
+ 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 (®no, &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/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp b/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
new file mode 100644
index 0000000..dda2308
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp b/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp
new file mode 100644
index 0000000..589c30b
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp b/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp
new file mode 100644
index 0000000..b11cb8c
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp b/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp
new file mode 100644
index 0000000..a4af020
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h b/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h
new file mode 100644
index 0000000..4048390
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/Registers.hpp b/source/Plugins/Process/Utility/libunwind/src/Registers.hpp
new file mode 100644
index 0000000..291c724
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/Registers.s b/source/Plugins/Process/Utility/libunwind/src/Registers.s
new file mode 100644
index 0000000..45dae3b
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp b/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp
new file mode 100644
index 0000000..1db3faf
--- /dev/null
+++ b/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, ®v, 0, arg))
+ newRegisters.setRegister(i, regv);
+ }
+ if (!addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, rmap->caller_regno_for_ip(), ®v, 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, ®v, 0, arg))
+ newRegisters.setRegister(i, regv);
+ }
+ if (!addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, rmap->caller_regno_for_ip(), ®v, 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/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp b/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp
new file mode 100644
index 0000000..3640dc6
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp b/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp
new file mode 100644
index 0000000..19caae9
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h b/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h
new file mode 100644
index 0000000..b03551c
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c b/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c
new file mode 100644
index 0000000..5845283
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp b/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp
new file mode 100644
index 0000000..e940b8b
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c b/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c
new file mode 100644
index 0000000..7103c71
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c b/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c
new file mode 100644
index 0000000..3aa2b6f
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/dwarf2.h b/source/Plugins/Process/Utility/libunwind/src/dwarf2.h
new file mode 100644
index 0000000..8341433
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h b/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h
new file mode 100644
index 0000000..fe25780
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx b/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx
new file mode 100644
index 0000000..e7e66a4
--- /dev/null
+++ b/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/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s b/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s
new file mode 100644
index 0000000..8d3a451
--- /dev/null
+++ b/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
+
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
new file mode 100644
index 0000000..cac2101
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -0,0 +1,813 @@
+//===-- GDBRemoteCommunication.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunication.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/TimeValue.h"
+
+// Project includes
+#include "StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunication constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::GDBRemoteCommunication() :
+ Communication("gdb-remote.packets"),
+ m_send_acks (true),
+ m_rx_packet_listener ("gdbremote.rx_packet"),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_is_running (false),
+ m_async_mutex (Mutex::eMutexTypeRecursive),
+ m_async_packet_predicate (false),
+ m_async_packet (),
+ m_async_response (),
+ m_async_timeout (UINT32_MAX),
+ m_async_signal (-1),
+ m_arch(),
+ m_os(),
+ m_vendor(),
+ m_byte_order(eByteOrderHost),
+ m_pointer_byte_size(0)
+{
+ m_rx_packet_listener.StartListeningForEvents(this,
+ Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::~GDBRemoteCommunication()
+{
+ m_rx_packet_listener.StopListeningForEvents(this,
+ Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit);
+ if (IsConnected())
+ {
+ StopReadThread();
+ Disconnect();
+ }
+}
+
+
+char
+GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length)
+{
+ int checksum = 0;
+
+ // We only need to compute the checksum if we are sending acks
+ if (m_send_acks)
+ {
+ for (int i = 0; i < payload_length; ++i)
+ checksum += payload[i];
+ }
+ return checksum & 255;
+}
+
+size_t
+GDBRemoteCommunication::SendAck (char ack_char)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: %c", ack_char);
+ ConnectionStatus status = eConnectionStatusSuccess;
+ return Write (&ack_char, 1, status, NULL) == 1;
+}
+
+size_t
+GDBRemoteCommunication::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async
+)
+{
+ return SendPacketAndWaitForResponse (payload,
+ ::strlen (payload),
+ response,
+ timeout_seconds,
+ send_async);
+}
+
+size_t
+GDBRemoteCommunication::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async
+)
+{
+ Mutex::Locker locker;
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (timeout_seconds);
+
+ if (locker.TryLock (m_sequence_mutex.GetMutex()))
+ {
+ if (SendPacketNoLock (payload, strlen(payload)))
+ return WaitForPacketNoLock (response, &timeout_time);
+ }
+ else
+ {
+ if (send_async)
+ {
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_packet.assign(payload, payload_length);
+ m_async_timeout = timeout_seconds;
+ m_async_packet_predicate.SetValue (true, eBroadcastNever);
+
+ bool timed_out = false;
+ if (SendInterrupt(1, &timed_out))
+ {
+ if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
+ {
+ response = m_async_response;
+ return response.GetStringRef().size();
+ }
+ }
+// if (timed_out)
+// m_error.SetErrorString("Timeout.");
+// else
+// m_error.SetErrorString("Unknown error.");
+ }
+ else
+ {
+// m_error.SetErrorString("Sequence mutex is locked.");
+ }
+ }
+ return 0;
+}
+
+//template<typename _Tp>
+//class ScopedValueChanger
+//{
+//public:
+// // Take a value reference and the value to assing it to when this class
+// // instance goes out of scope.
+// ScopedValueChanger (_Tp &value_ref, _Tp value) :
+// m_value_ref (value_ref),
+// m_value (value)
+// {
+// }
+//
+// // This object is going out of scope, change the value pointed to by
+// // m_value_ref to the value we got during construction which was stored in
+// // m_value;
+// ~ScopedValueChanger ()
+// {
+// m_value_ref = m_value;
+// }
+//protected:
+// _Tp &m_value_ref; // A reference to the value we wil change when this object destructs
+// _Tp m_value; // The value to assign to m_value_ref when this goes out of scope.
+//};
+
+StateType
+GDBRemoteCommunication::SendContinuePacketAndWaitForResponse
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s ()", __FUNCTION__);
+
+ Mutex::Locker locker(m_sequence_mutex);
+ m_is_running.SetValue (true, eBroadcastNever);
+
+// ScopedValueChanger<bool> restore_running_to_false (m_is_running, false);
+ StateType state = eStateRunning;
+
+ if (SendPacket(payload, packet_length) == 0)
+ state = eStateInvalid;
+
+ while (state == eStateRunning)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () WaitForPacket(...)", __FUNCTION__);
+
+ if (WaitForPacket (response, (TimeValue*)NULL))
+ {
+ if (response.Empty())
+ state = eStateInvalid;
+ else
+ {
+ const char stop_type = response.GetChar();
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () got '%c' packet", __FUNCTION__, stop_type);
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ if (m_async_signal != -1)
+ {
+ // Save off the async signal we are supposed to send
+ const int async_signal = m_async_signal;
+ // Clear the async signal member so we don't end up
+ // sending the signal multiple times...
+ m_async_signal = -1;
+ // Check which signal we stopped with
+ uint8_t signo = response.GetHexU8(255);
+ if (signo == async_signal)
+ {
+ // We already stopped with a signal that we wanted
+ // to stop with, so we are done
+ response.SetFilePos (0);
+ }
+ else
+ {
+ // We stopped with a different signal that the one
+ // we wanted to stop with, so now we must resume
+ // with the signal we want
+ char signal_packet[32];
+ int signal_packet_len = 0;
+ signal_packet_len = ::snprintf (signal_packet,
+ sizeof (signal_packet),
+ "C%2.2x",
+ async_signal);
+
+ if (SendPacket(signal_packet, signal_packet_len) == 0)
+ {
+ state = eStateInvalid;
+ break;
+ }
+ else
+ continue;
+ }
+ }
+ else if (m_async_packet_predicate.GetValue())
+ {
+ // We are supposed to send an asynchronous packet while
+ // we are running.
+ m_async_response.Clear();
+ if (!m_async_packet.empty())
+ {
+ SendPacketAndWaitForResponse (m_async_packet.data(),
+ m_async_packet.size(),
+ m_async_response,
+ m_async_timeout,
+ false);
+ }
+ // Let the other thread that was trying to send the async
+ // packet know that the packet has been sent.
+ m_async_packet_predicate.SetValue(false, eBroadcastAlways);
+
+ // Continue again
+ if (SendPacket("c", 1) == 0)
+ {
+ state = eStateInvalid;
+ break;
+ }
+ else
+ continue;
+ }
+ // Stop with signal and thread info
+ state = eStateStopped;
+ break;
+
+ case 'W':
+ // process exited
+ state = eStateExited;
+ break;
+
+ case 'O':
+ // STDOUT
+ {
+ std::string inferior_stdout;
+ inferior_stdout.reserve(response.GetBytesLeft () / 2);
+ char ch;
+ while ((ch = response.GetHexU8()) != '\0')
+ inferior_stdout.append(1, ch);
+ process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size());
+ }
+ break;
+
+ case 'E':
+ // ERROR
+ state = eStateInvalid;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () got unrecognized async packet: '%s'", __FUNCTION__, stop_type);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () WaitForPacket(...) => false", __FUNCTION__);
+ state = eStateInvalid;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () => %s", __FUNCTION__, StateAsCString(state));
+ response.SetFilePos(0);
+ m_is_running.SetValue (false, eBroadcastOnChange);
+ return state;
+}
+
+size_t
+GDBRemoteCommunication::SendPacket (const char *payload)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, ::strlen (payload));
+}
+
+size_t
+GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, payload_length);
+}
+
+size_t
+GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length)
+{
+ if (IsConnected())
+ {
+ StreamString packet(0, 4, eByteOrderBig);
+
+ packet.PutChar('$');
+ packet.Write (payload, payload_length);
+ packet.PutChar('#');
+ packet.PutHex8(CalculcateChecksum (payload, payload_length));
+
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: %s", packet.GetData());
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
+ if (bytes_written == packet.GetSize())
+ {
+ if (m_send_acks)
+ GetAck (1) == '+';
+ }
+ return bytes_written;
+ }
+ //m_error.SetErrorString("Not connected.");
+ return 0;
+}
+
+char
+GDBRemoteCommunication::GetAck (uint32_t timeout_seconds)
+{
+ StringExtractorGDBRemote response;
+ if (WaitForPacket (response, timeout_seconds) == 1)
+ return response.GetChar();
+ return 0;
+}
+
+bool
+GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker)
+{
+ return locker.TryLock (m_sequence_mutex.GetMutex());
+}
+
+bool
+GDBRemoteCommunication::SendAsyncSignal (int signo)
+{
+ m_async_signal = signo;
+ bool timed_out = false;
+ if (SendInterrupt(1, &timed_out))
+ return true;
+ m_async_signal = -1;
+ return false;
+}
+
+bool
+GDBRemoteCommunication::SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *timed_out)
+{
+ if (timed_out)
+ *timed_out = false;
+
+ if (IsConnected() && IsRunning())
+ {
+ // Only send an interrupt if our debugserver is running...
+ if (m_sequence_mutex.TryLock() != 0)
+ {
+ // Someone has the mutex locked waiting for a response or for the
+ // inferior to stop, so send the interrupt on the down low...
+ char ctrl_c = '\x03';
+ ConnectionStatus status = eConnectionStatusSuccess;
+ TimeValue timeout;
+ if (seconds_to_wait_for_stop)
+ {
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (seconds_to_wait_for_stop);
+ }
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: \\x03");
+ if (Write (&ctrl_c, 1, status, NULL) > 0)
+ {
+ if (seconds_to_wait_for_stop)
+ m_is_running.WaitForValueEqualTo (false, &timeout, timed_out);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, uint32_t timeout_seconds)
+{
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (timeout_seconds);
+ return WaitForPacketNoLock (response, &timeout_time);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return WaitForPacketNoLock (response, timeout_time_ptr);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+{
+ bool checksum_error = false;
+ response.Clear ();
+
+ EventSP event_sp;
+
+ if (m_rx_packet_listener.WaitForEvent (timeout_time_ptr, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_type | Communication::eBroadcastBitPacketAvailable)
+ {
+ const EventDataBytes *event_bytes = EventDataBytes::GetEventDataFromEvent(event_sp.get());
+ if (event_bytes)
+ {
+ const char * packet_data = (const char *)event_bytes->GetBytes();
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "read packet: %s", packet_data);
+ const size_t packet_size = event_bytes->GetByteSize();
+ if (packet_data && packet_size > 0)
+ {
+ std::string &response_str = response.GetStringRef();
+ if (packet_data[0] == '$')
+ {
+ assert (packet_size >= 4); // Must have at least '$#CC' where CC is checksum
+ assert (packet_data[packet_size-3] == '#');
+ assert (::isxdigit (packet_data[packet_size-2])); // Must be checksum hex byte
+ assert (::isxdigit (packet_data[packet_size-1])); // Must be checksum hex byte
+ response_str.assign (packet_data + 1, packet_size - 4);
+ if (m_send_acks)
+ {
+ char packet_checksum = strtol (&packet_data[packet_size-2], NULL, 16);
+ char actual_checksum = CalculcateChecksum (response_str.data(), response_str.size());
+ checksum_error = packet_checksum != actual_checksum;
+ // Send the ack or nack if needed
+ if (checksum_error)
+ SendAck('-');
+ else
+ SendAck('+');
+ }
+ }
+ else
+ {
+ response_str.assign (packet_data, packet_size);
+ }
+ return response_str.size();
+ }
+ }
+ }
+ else if (Communication::eBroadcastBitReadThreadDidExit)
+ {
+ // Our read thread exited on us so just fall through and return zero...
+ }
+ }
+ return 0;
+}
+
+void
+GDBRemoteCommunication::AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+ m_bytes.append ((const char *)src, src_len);
+
+ // Parse up the packets into gdb remote packets
+ while (!m_bytes.empty())
+ {
+ // end_idx must be one past the last valid packet byte. Start
+ // it off with an invalid value that is the same as the current
+ // index.
+ size_t end_idx = 0;
+
+ switch (m_bytes[0])
+ {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ end_idx = 1; // The command is one byte long...
+ break;
+
+ case '$':
+ // Look for a standard gdb packet?
+ end_idx = m_bytes.find('#');
+ if (end_idx != std::string::npos)
+ {
+ if (end_idx + 2 < m_bytes.size())
+ {
+ end_idx += 3;
+ }
+ else
+ {
+ // Checksum bytes aren't all here yet
+ end_idx = std::string::npos;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (end_idx == std::string::npos)
+ {
+ //ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE, "GDBRemoteCommunication::%s packet not yet complete: '%s'",__FUNCTION__, m_bytes.c_str());
+ return;
+ }
+ else if (end_idx > 0)
+ {
+ // We have a valid packet...
+ assert (end_idx <= m_bytes.size());
+ std::auto_ptr<EventDataBytes> event_bytes_ap (new EventDataBytes (&m_bytes[0], end_idx));
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_COMM, "got full packet: %s", event_bytes_ap->GetBytes());
+ BroadcastEvent (eBroadcastBitPacketAvailable, event_bytes_ap.release());
+ m_bytes.erase(0, end_idx);
+ }
+ else
+ {
+ assert (1 <= m_bytes.size());
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_COMM, "GDBRemoteCommunication::%s tossing junk byte at %c",__FUNCTION__, m_bytes[0]);
+ m_bytes.erase(0, 1);
+ }
+ }
+}
+
+lldb::pid_t
+GDBRemoteCommunication::GetCurrentProcessID (uint32_t timeout_seconds)
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, timeout_seconds, false))
+ {
+ if (response.GetChar() == 'Q')
+ if (response.GetChar() == 'C')
+ return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+bool
+GDBRemoteCommunication::GetLaunchSuccess (uint32_t timeout_seconds, std::string &error_str)
+{
+ error_str.clear();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return true;
+ if (response.GetChar() == 'E')
+ {
+ // A string the describes what failed when launching...
+ error_str = response.GetStringRef().substr(1);
+ }
+ else
+ {
+ error_str.assign ("unknown error occurred launching process");
+ }
+ }
+ else
+ {
+ error_str.assign ("failed to send the qLaunchSuccess packet");
+ }
+ return false;
+}
+
+int
+GDBRemoteCommunication::SendArgumentsPacket (char const *argv[], uint32_t timeout_seconds)
+{
+ if (argv && argv[0])
+ {
+ StreamString packet;
+ packet.PutChar('A');
+ const char *arg;
+ for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i)
+ {
+ const int arg_len = strlen(arg);
+ if (i > 0)
+ packet.PutChar(',');
+ packet.Printf("%i,%i,", arg_len * 2, i);
+ packet.PutBytesAsRawHex8(arg, arg_len, eByteOrderHost, eByteOrderHost);
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunication::SendEnvironmentPacket (char const *name_equal_value, uint32_t timeout_seconds)
+{
+ if (name_equal_value && name_equal_value[0])
+ {
+ StreamString packet;
+ packet.Printf("QEnvironment:%s", name_equal_value);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunication::GetHostInfo (uint32_t timeout_seconds)
+{
+ m_arch.Clear();
+ m_os.Clear();
+ m_vendor.Clear();
+ m_byte_order = eByteOrderHost;
+ m_pointer_byte_size = 0;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qHostInfo", response, timeout_seconds, false))
+ {
+ if (response.IsUnsupportedPacket())
+ return false;
+
+
+ std::string name;
+ std::string value;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ // exception type in big endian hex
+ m_arch.SetCPUType(Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0));
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ // exception count in big endian hex
+ m_arch.SetCPUSubtype(Args::StringToUInt32 (value.c_str(), 0, 0));
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ // exception data in big endian hex
+ m_os.SetCString(value.c_str());
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ m_vendor.SetCString(value.c_str());
+ }
+ else if (name.compare("endian") == 0)
+ {
+ if (value.compare("little") == 0)
+ m_byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ m_byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ m_byte_order = eByteOrderPDP;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ m_pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 0);
+ }
+ }
+ }
+ return HostInfoIsValid();
+}
+
+int
+GDBRemoteCommunication::SendAttach
+(
+ lldb::pid_t pid,
+ uint32_t timeout_seconds,
+ StringExtractorGDBRemote& response
+)
+{
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ StreamString packet;
+ packet.Printf("vAttach;%x", pid);
+
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsErrorPacket())
+ return response.GetError();
+ return 0;
+ }
+ }
+ return -1;
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunication::GetHostArchitecture ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_arch;
+}
+
+const lldb_private::ConstString &
+GDBRemoteCommunication::GetOSString ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_os;
+}
+
+const lldb_private::ConstString &
+GDBRemoteCommunication::GetVendorString()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_vendor;
+}
+
+lldb::ByteOrder
+GDBRemoteCommunication::GetByteOrder ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_byte_order;
+}
+
+uint32_t
+GDBRemoteCommunication::GetAddressByteSize ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_pointer_byte_size;
+}
+
+addr_t
+GDBRemoteCommunication::AllocateMemory (size_t size, uint32_t permissions, uint32_t timeout_seconds)
+{
+ char packet[64];
+ ::snprintf (packet, sizeof(packet), "_M%zx,%s%s%s", size,
+ permissions & lldb::ePermissionsReadable ? "r" : "",
+ permissions & lldb::ePermissionsWritable ? "w" : "",
+ permissions & lldb::ePermissionsExecutable ? "x" : "");
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, response, timeout_seconds, false))
+ {
+ if (!response.IsErrorPacket())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+GDBRemoteCommunication::DeallocateMemory (addr_t addr, uint32_t timeout_seconds)
+{
+ char packet[64];
+ snprintf(packet, sizeof(packet), "_m%llx", (uint64_t)addr);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, response, timeout_seconds, false))
+ {
+ if (!response.IsOKPacket())
+ return true;
+ }
+ return false;
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
new file mode 100644
index 0000000..051fa44
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -0,0 +1,270 @@
+//===-- GDBRemoteCommunication.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_GDBRemoteCommunication_h_
+#define liblldb_GDBRemoteCommunication_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+
+#include "StringExtractorGDBRemote.h"
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunication :
+ public lldb_private::Communication
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunication();
+
+ virtual
+ ~GDBRemoteCommunication();
+
+ size_t
+ SendPacket (const char *payload);
+
+ size_t
+ SendPacket (const char *payload,
+ size_t payload_length);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ size_t send_length,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async);
+
+ lldb::StateType
+ SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,
+ const char *packet_payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response);
+
+ // Wait for a packet within 'nsec' seconds
+ size_t
+ WaitForPacket (StringExtractorGDBRemote &response,
+ uint32_t nsec);
+
+ // Wait for a packet with an absolute timeout time. If 'timeout' is NULL
+ // wait indefinitely.
+ size_t
+ WaitForPacket (StringExtractorGDBRemote &response,
+ lldb_private::TimeValue* timeout);
+
+ char
+ GetAck (uint32_t timeout_seconds);
+
+ size_t
+ SendAck (char ack_char);
+
+ char
+ CalculcateChecksum (const char *payload,
+ size_t payload_length);
+
+ void
+ SetAckMode (bool enabled)
+ {
+ m_send_acks = enabled;
+ }
+
+ bool
+ SendAsyncSignal (int signo);
+
+ bool
+ SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *timed_out = NULL);
+
+ bool
+ GetSequenceMutex(lldb_private::Mutex::Locker& locker);
+
+ //------------------------------------------------------------------
+ // Communication overrides
+ //------------------------------------------------------------------
+ virtual void
+ AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast);
+
+
+ lldb::pid_t
+ GetCurrentProcessID (uint32_t timeout_seconds);
+
+ bool
+ GetLaunchSuccess (uint32_t timeout_seconds, std::string &error_str);
+
+ //------------------------------------------------------------------
+ /// Sends a GDB remote protocol 'A' packet that delivers program
+ /// arguments to the remote server.
+ ///
+ /// @param[in] argv
+ /// A NULL terminated array of const C strings to use as the
+ /// arguments.
+ ///
+ /// @param[in] timeout_seconds
+ /// The number of seconds to wait for a response from the remote
+ /// server.
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendArgumentsPacket (char const *argv[], uint32_t timeout_seconds);
+
+ //------------------------------------------------------------------
+ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
+ /// environment that will get used when launching an application
+ /// in conjunction with the 'A' packet. This function can be called
+ /// multiple times in a row in order to pass on the desired
+ /// environment that the inferior should be launched with.
+ ///
+ /// @param[in] name_equal_value
+ /// A NULL terminated C string that contains a single enironment
+ /// in the format "NAME=VALUE".
+ ///
+ /// @param[in] timeout_seconds
+ /// The number of seconds to wait for a response from the remote
+ /// server.
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendEnvironmentPacket (char const *name_equal_value,
+ uint32_t timeout_seconds);
+
+ //------------------------------------------------------------------
+ /// Sends a "vAttach:PID" where PID is in hex.
+ ///
+ /// @param[in] pid
+ /// A process ID for the remote gdb server to attach to.
+ ///
+ /// @param[in] timeout_seconds
+ /// The number of seconds to wait for a response from the remote
+ /// server.
+ ///
+ /// @param[out] response
+ /// The response received from the gdb server. If the return
+ /// value is zero, \a response will contain a stop reply
+ /// packet.
+ ///
+ /// @return
+ /// Zero if the attach was successful, or an error indicating
+ /// an error code.
+ //------------------------------------------------------------------
+ int
+ SendAttach (lldb::pid_t pid,
+ uint32_t timeout_seconds,
+ StringExtractorGDBRemote& response);
+
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions, uint32_t timeout_seconds);
+
+ bool
+ DeallocateMemory (lldb::addr_t addr, uint32_t timeout_seconds);
+
+ bool
+ IsRunning() const
+ {
+ return m_is_running.GetValue();
+ }
+
+ bool
+ GetHostInfo (uint32_t timeout_seconds);
+
+ bool
+ HostInfoIsValid () const
+ {
+ return m_pointer_byte_size != 0;
+ }
+
+ const lldb_private::ArchSpec &
+ GetHostArchitecture ();
+
+ const lldb_private::ConstString &
+ GetOSString ();
+
+ const lldb_private::ConstString &
+ GetVendorString();
+
+ lldb::ByteOrder
+ GetByteOrder ();
+
+ uint32_t
+ GetAddressByteSize ();
+
+protected:
+ typedef std::list<std::string> packet_collection;
+
+ size_t
+ SendPacketNoLock (const char *payload,
+ size_t payload_length);
+
+ size_t
+ WaitForPacketNoLock (StringExtractorGDBRemote &response,
+ lldb_private::TimeValue* timeout_time_ptr);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunication can see and modify these
+ //------------------------------------------------------------------
+ bool m_send_acks;
+ lldb_private::Listener m_rx_packet_listener;
+ lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
+ lldb_private::Predicate<bool> m_is_running;
+
+ // If we need to send a packet while the target is running, the m_async_XXX
+ // member variables take care of making this happen.
+ lldb_private::Mutex m_async_mutex;
+ lldb_private::Predicate<bool> m_async_packet_predicate;
+ std::string m_async_packet;
+ StringExtractorGDBRemote m_async_response;
+ uint32_t m_async_timeout;
+ int m_async_signal; // We were asked to deliver a signal to the inferior process.
+
+ lldb_private::ArchSpec m_arch; // Results from the qHostInfo call
+ uint32_t m_cpusubtype; // Results from the qHostInfo call
+ lldb_private::ConstString m_os; // Results from the qHostInfo call
+ lldb_private::ConstString m_vendor; // Results from the qHostInfo call
+ lldb::ByteOrder m_byte_order; // Results from the qHostInfo call
+ uint32_t m_pointer_byte_size; // Results from the qHostInfo call
+
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunication only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication);
+};
+
+#endif // liblldb_GDBRemoteCommunication_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
new file mode 100644
index 0000000..a64e74d
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -0,0 +1,508 @@
+//===-- GDBRemoteRegisterContext.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteRegisterContext.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"
+// Project includes
+#include "StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ThreadGDBRemote.h"
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteRegisterContext constructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::GDBRemoteRegisterContext
+(
+ ThreadGDBRemote &thread,
+ StackFrame *frame,
+ GDBRemoteDynamicRegisterInfo ®_info,
+ bool read_all_at_once
+) :
+ RegisterContext (thread, frame),
+ m_reg_info (reg_info),
+ m_reg_valid (),
+ m_reg_data (),
+ m_read_all_at_once (read_all_at_once)
+{
+ // Resize our vector of bools to contain one bool for every register.
+ // We will use these boolean values to know when a register value
+ // is valid in m_reg_data.
+ m_reg_valid.resize (reg_info.GetNumRegisters());
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::~GDBRemoteRegisterContext()
+{
+}
+
+ProcessGDBRemote &
+GDBRemoteRegisterContext::GetGDBProcess()
+{
+ return static_cast<ProcessGDBRemote &>(m_thread.GetProcess());
+}
+
+ThreadGDBRemote &
+GDBRemoteRegisterContext::GetGDBThread()
+{
+ return static_cast<ThreadGDBRemote &>(m_thread);
+}
+
+void
+GDBRemoteRegisterContext::Invalidate ()
+{
+ SetAllRegisterValid (false);
+}
+
+void
+GDBRemoteRegisterContext::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterCount ()
+{
+ return m_reg_info.GetNumRegisters ();
+}
+
+const lldb::RegisterInfo *
+GDBRemoteRegisterContext::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ return m_reg_info.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterSetCount ()
+{
+ return m_reg_info.GetNumRegisterSets ();
+}
+
+
+
+const lldb::RegisterSet *
+GDBRemoteRegisterContext::GetRegisterSet (uint32_t reg_set)
+{
+ return m_reg_info.GetRegisterSet (reg_set);
+}
+
+
+
+bool
+GDBRemoteRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ // Read the register
+ if (ReadRegisterBytes (reg, m_reg_data))
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ uint32_t offset = reg_info->byte_offset;
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = m_reg_data.GetMaxU32 (&offset, reg_info->byte_size);
+ return true;
+
+ case 8:
+ value = m_reg_data.GetMaxU64 (&offset, reg_info->byte_size);
+ return true;
+ }
+ break;
+
+ case eEncodingSint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (int32_t)m_reg_data.GetMaxU32 (&offset, reg_info->byte_size);
+ return true;
+
+ case 8:
+ value = m_reg_data.GetMaxS64 (&offset, reg_info->byte_size);
+ return true;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ value = m_reg_data.GetFloat (&offset);
+ return true;
+
+ case sizeof (double):
+ value = m_reg_data.GetDouble (&offset);
+ return true;
+
+ case sizeof (long double):
+ value = m_reg_data.GetLongDouble (&offset);
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
+// FIXME: This check isn't right because IsRunning checks the Public state, but this
+// is work you need to do - for instance in ShouldStop & friends - before the public
+// state has been changed.
+// if (gdb_comm.IsRunning())
+// return false;
+
+ if (m_reg_valid_stop_id != m_thread.GetProcess().GetStopID())
+ {
+ Invalidate();
+ m_reg_valid_stop_id = m_thread.GetProcess().GetStopID();
+ }
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ assert (reg_info);
+ if (m_reg_valid[reg] == false)
+ {
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker))
+ {
+ if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
+ {
+ char packet[32];
+ StringExtractorGDBRemote response;
+ int packet_len;
+ if (m_read_all_at_once)
+ {
+ // Get all registers in one packet
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < (sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
+ {
+ if (response.IsNormalPacket())
+ if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
+ SetAllRegisterValid (true);
+ }
+ }
+ else
+ {
+ // Get each register individually
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg, false);
+ assert (packet_len < (sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
+ if (response.GetHexBytes ((uint8_t*)m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), reg_info->byte_size, '\xcc') == reg_info->byte_size)
+ m_reg_valid[reg] = true;
+ }
+ }
+ }
+ }
+
+ bool reg_is_valid = m_reg_valid[reg];
+ if (reg_is_valid)
+ {
+ if (&data != &m_reg_data)
+ {
+ // If we aren't extracting into our own buffer (which
+ // only happens when this function is called from
+ // ReadRegisterValue(uint32_t, Scalar&)) then
+ // we transfer bytes from our buffer into the data
+ // buffer that was passed in
+ data.SetByteOrder (m_reg_data.GetByteOrder());
+ data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size);
+ }
+ }
+ return reg_is_valid;
+}
+
+
+bool
+GDBRemoteRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info)
+ {
+ DataExtractor data;
+ if (value.GetData (data, reg_info->byte_size))
+ return WriteRegisterBytes (reg, data, 0);
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
+// FIXME: This check isn't right because IsRunning checks the Public state, but this
+// is work you need to do - for instance in ShouldStop & friends - before the public
+// state has been changed.
+// if (gdb_comm.IsRunning())
+// return false;
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+
+ if (reg_info)
+ {
+ // Grab a pointer to where we are going to put this register
+ uint8_t *dst = (uint8_t *)m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size);
+
+ if (dst == NULL)
+ return false;
+
+ // Grab a pointer to where we are going to grab the new value from
+ const uint8_t *src = data.PeekData(0, reg_info->byte_size);
+
+ if (src == NULL)
+ return false;
+
+ if (data.GetByteOrder() == m_reg_data.GetByteOrder())
+ {
+ // No swapping, just copy the bytes
+ ::memcpy (dst, src, reg_info->byte_size);
+ }
+ else
+ {
+ // Swap the bytes
+ for (uint32_t i=0; i<reg_info->byte_size; ++i)
+ dst[i] = src[reg_info->byte_size - 1 - i];
+ }
+
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker))
+ {
+ if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
+ {
+ uint32_t offset, end_offset;
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ if (m_read_all_at_once)
+ {
+ // Get all registers in one packet
+ packet.PutChar ('G');
+ offset = 0;
+ end_offset = m_reg_data.GetByteSize();
+
+ packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
+ m_reg_data.GetByteSize(),
+ eByteOrderHost,
+ eByteOrderHost);
+
+ // Invalidate all register values
+ Invalidate ();
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ 1,
+ false))
+ {
+ SetAllRegisterValid (false);
+ if (response.IsOKPacket())
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ // Get each register individually
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
+ reg_info->byte_size,
+ eByteOrderHost,
+ eByteOrderHost);
+
+ // Invalidate just this register
+ m_reg_valid[reg] = false;
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ 1,
+ false))
+ {
+ if (response.IsOKPacket())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
+ StringExtractorGDBRemote response;
+ if (gdb_comm.SendPacketAndWaitForResponse("g", response, 1, false))
+ {
+ if (response.IsErrorPacket())
+ return false;
+
+ response.GetStringRef().insert(0, 1, 'G');
+ data_sp.reset (new DataBufferHeap(response.GetStringRef().data(),
+ response.GetStringRef().size()));
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
+ StringExtractorGDBRemote response;
+ if (gdb_comm.SendPacketAndWaitForResponse((const char *)data_sp->GetBytes(),
+ data_sp->GetByteSize(),
+ response,
+ 1,
+ false))
+ {
+ if (response.IsOKPacket())
+ return true;
+ }
+ return false;
+}
+
+
+uint32_t
+GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+void
+GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters()
+{
+ static lldb::RegisterInfo
+ g_register_infos[] =
+ {
+ // NAME ALT SZ OFF ENCODING FORMAT NUM COMPILER DWARF GENERIC
+ // ====== ======= == ==== ============= ============ === =============== =============== =========
+ { "r0", NULL, 4, 0, eEncodingUint, eFormatHex, 0, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM }},
+ { "r1", NULL, 4, 4, eEncodingUint, eFormatHex, 1, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM }},
+ { "r2", NULL, 4, 8, eEncodingUint, eFormatHex, 2, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM }},
+ { "r3", NULL, 4, 12, eEncodingUint, eFormatHex, 3, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM }},
+ { "r4", NULL, 4, 16, eEncodingUint, eFormatHex, 4, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM }},
+ { "r5", NULL, 4, 20, eEncodingUint, eFormatHex, 5, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM }},
+ { "r6", NULL, 4, 24, eEncodingUint, eFormatHex, 6, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM }},
+ { "r7", NULL, 4, 28, eEncodingUint, eFormatHex, 7, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP }},
+ { "r8", NULL, 4, 32, eEncodingUint, eFormatHex, 8, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM }},
+ { "r9", NULL, 4, 36, eEncodingUint, eFormatHex, 9, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM }},
+ { "r10", NULL, 4, 40, eEncodingUint, eFormatHex, 10, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM }},
+ { "r11", NULL, 4, 44, eEncodingUint, eFormatHex, 11, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM }},
+ { "r12", NULL, 4, 48, eEncodingUint, eFormatHex, 12, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM }},
+ { "sp", "r13", 4, 52, eEncodingUint, eFormatHex, 13, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP }},
+ { "lr", "r14", 4, 56, eEncodingUint, eFormatHex, 14, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA }},
+ { "pc", "r15", 4, 60, eEncodingUint, eFormatHex, 15, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC }},
+ { NULL, NULL, 12, 64, eEncodingIEEE754, eFormatFloat, 16, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 76, eEncodingIEEE754, eFormatFloat, 17, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 88, eEncodingIEEE754, eFormatFloat, 18, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 100, eEncodingIEEE754, eFormatFloat, 19, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 112, eEncodingIEEE754, eFormatFloat, 20, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 124, eEncodingIEEE754, eFormatFloat, 21, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 136, eEncodingIEEE754, eFormatFloat, 22, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 148, eEncodingIEEE754, eFormatFloat, 23, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 160, eEncodingIEEE754, eFormatFloat, 24, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { "cpsr", "psr", 4, 172, eEncodingUint, eFormatHex, 25, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS }},
+ { "s0", NULL, 4, 176, eEncodingIEEE754, eFormatFloat, 26, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM }},
+ { "s1", NULL, 4, 180, eEncodingIEEE754, eFormatFloat, 27, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM }},
+ { "s2", NULL, 4, 184, eEncodingIEEE754, eFormatFloat, 28, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM }},
+ { "s3", NULL, 4, 188, eEncodingIEEE754, eFormatFloat, 29, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM }},
+ { "s4", NULL, 4, 192, eEncodingIEEE754, eFormatFloat, 30, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM }},
+ { "s5", NULL, 4, 196, eEncodingIEEE754, eFormatFloat, 31, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM }},
+ { "s6", NULL, 4, 200, eEncodingIEEE754, eFormatFloat, 32, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM }},
+ { "s7", NULL, 4, 204, eEncodingIEEE754, eFormatFloat, 33, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM }},
+ { "s8", NULL, 4, 208, eEncodingIEEE754, eFormatFloat, 34, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM }},
+ { "s9", NULL, 4, 212, eEncodingIEEE754, eFormatFloat, 35, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM }},
+ { "s10", NULL, 4, 216, eEncodingIEEE754, eFormatFloat, 36, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM }},
+ { "s11", NULL, 4, 220, eEncodingIEEE754, eFormatFloat, 37, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM }},
+ { "s12", NULL, 4, 224, eEncodingIEEE754, eFormatFloat, 38, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM }},
+ { "s13", NULL, 4, 228, eEncodingIEEE754, eFormatFloat, 39, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM }},
+ { "s14", NULL, 4, 232, eEncodingIEEE754, eFormatFloat, 40, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM }},
+ { "s15", NULL, 4, 236, eEncodingIEEE754, eFormatFloat, 41, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM }},
+ { "s16", NULL, 4, 240, eEncodingIEEE754, eFormatFloat, 42, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM }},
+ { "s17", NULL, 4, 244, eEncodingIEEE754, eFormatFloat, 43, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM }},
+ { "s18", NULL, 4, 248, eEncodingIEEE754, eFormatFloat, 44, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM }},
+ { "s19", NULL, 4, 252, eEncodingIEEE754, eFormatFloat, 45, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM }},
+ { "s20", NULL, 4, 256, eEncodingIEEE754, eFormatFloat, 46, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM }},
+ { "s21", NULL, 4, 260, eEncodingIEEE754, eFormatFloat, 47, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM }},
+ { "s22", NULL, 4, 264, eEncodingIEEE754, eFormatFloat, 48, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM }},
+ { "s23", NULL, 4, 268, eEncodingIEEE754, eFormatFloat, 49, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM }},
+ { "s24", NULL, 4, 272, eEncodingIEEE754, eFormatFloat, 50, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM }},
+ { "s25", NULL, 4, 276, eEncodingIEEE754, eFormatFloat, 51, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM }},
+ { "s26", NULL, 4, 280, eEncodingIEEE754, eFormatFloat, 52, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM }},
+ { "s27", NULL, 4, 284, eEncodingIEEE754, eFormatFloat, 53, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM }},
+ { "s28", NULL, 4, 288, eEncodingIEEE754, eFormatFloat, 54, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM }},
+ { "s29", NULL, 4, 292, eEncodingIEEE754, eFormatFloat, 55, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM }},
+ { "s30", NULL, 4, 296, eEncodingIEEE754, eFormatFloat, 56, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM }},
+ { "s31", NULL, 4, 300, eEncodingIEEE754, eFormatFloat, 57, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM }},
+ { "fpscr", NULL, 4, 304, eEncodingUint, eFormatHex, 58, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM }},
+ { "d16", NULL, 8, 308, eEncodingIEEE754, eFormatFloat, 59, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM }},
+ { "d17", NULL, 8, 316, eEncodingIEEE754, eFormatFloat, 60, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM }},
+ { "d18", NULL, 8, 324, eEncodingIEEE754, eFormatFloat, 61, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM }},
+ { "d19", NULL, 8, 332, eEncodingIEEE754, eFormatFloat, 62, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM }},
+ { "d20", NULL, 8, 340, eEncodingIEEE754, eFormatFloat, 63, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM }},
+ { "d21", NULL, 8, 348, eEncodingIEEE754, eFormatFloat, 64, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM }},
+ { "d22", NULL, 8, 356, eEncodingIEEE754, eFormatFloat, 65, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM }},
+ { "d23", NULL, 8, 364, eEncodingIEEE754, eFormatFloat, 66, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM }},
+ { "d24", NULL, 8, 372, eEncodingIEEE754, eFormatFloat, 67, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM }},
+ { "d25", NULL, 8, 380, eEncodingIEEE754, eFormatFloat, 68, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM }},
+ { "d26", NULL, 8, 388, eEncodingIEEE754, eFormatFloat, 69, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM }},
+ { "d27", NULL, 8, 396, eEncodingIEEE754, eFormatFloat, 70, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM }},
+ { "d28", NULL, 8, 404, eEncodingIEEE754, eFormatFloat, 71, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM }},
+ { "d29", NULL, 8, 412, eEncodingIEEE754, eFormatFloat, 72, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM }},
+ { "d30", NULL, 8, 420, eEncodingIEEE754, eFormatFloat, 73, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM }},
+ { "d31", NULL, 8, 428, eEncodingIEEE754, eFormatFloat, 74, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM }},
+ };
+ static const uint32_t num_registers = sizeof (g_register_infos)/sizeof (lldb::RegisterInfo);
+ static ConstString gpr_reg_set ("General Purpose Registers");
+ static ConstString vfp_reg_set ("Floating Point Registers");
+ for (uint32_t i=0; i<num_registers; ++i)
+ {
+ ConstString name;
+ ConstString alt_name;
+ if (g_register_infos[i].name && g_register_infos[i].name[0])
+ name.SetCString(g_register_infos[i].name);
+ if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0])
+ alt_name.SetCString(g_register_infos[i].alt_name);
+
+ AddRegister (g_register_infos[i], name, alt_name, i < 26 ? gpr_reg_set : vfp_reg_set);
+ }
+}
+
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
new file mode 100644
index 0000000..67acdef
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -0,0 +1,250 @@
+//===-- GDBRemoteRegisterContext.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_GDBRemoteRegisterContext_h_
+#define lldb_GDBRemoteRegisterContext_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+
+
+class ThreadGDBRemote;
+class ProcessGDBRemote;
+
+class GDBRemoteDynamicRegisterInfo
+{
+public:
+ GDBRemoteDynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_reg_names (),
+ m_reg_alt_names (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+ {
+ }
+
+ ~GDBRemoteDynamicRegisterInfo ()
+ {
+ }
+
+ void
+ AddRegister (lldb::RegisterInfo ®_info, lldb_private::ConstString ®_name, lldb_private::ConstString ®_alt_name, lldb_private::ConstString &set_name)
+ {
+ const uint32_t reg_num = m_regs.size();
+ m_reg_names.push_back (reg_name);
+ m_reg_alt_names.push_back (reg_alt_name);
+ reg_info.name = reg_name.AsCString();
+ assert (reg_info.name);
+ reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ m_regs.push_back (reg_info);
+ uint32_t set = GetRegisterSetIndexByName (set_name, true);
+ assert (set < m_sets.size());
+ assert (set < m_set_reg_nums.size());
+ assert (set < m_set_names.size());
+ m_set_reg_nums[set].push_back(reg_num);
+ size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+ }
+
+ void
+ Finalize ()
+ {
+ for (uint32_t set = 0; set < m_sets.size(); ++set)
+ {
+ assert (m_sets.size() == m_set_reg_nums.size());
+ m_sets[set].num_registers = m_set_reg_nums[set].size();
+ m_sets[set].registers = &m_set_reg_nums[set][0];
+ }
+ }
+
+ size_t
+ GetNumRegisters() const
+ {
+ return m_regs.size();
+ }
+
+ size_t
+ GetNumRegisterSets() const
+ {
+ return m_sets.size();
+ }
+
+ size_t
+ GetRegisterDataByteSize() const
+ {
+ return m_reg_data_byte_size;
+ }
+
+ const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const
+ {
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+ }
+
+ const lldb::RegisterSet *
+ GetRegisterSet (uint32_t i) const
+ {
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+ }
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name, bool can_create)
+ {
+ name_collection::iterator pos, end = m_set_names.end();
+ for (pos = m_set_names.begin(); pos != end; ++pos)
+ {
+ if (*pos == set_name)
+ return std::distance (m_set_names.begin(), pos);
+ }
+
+ m_set_names.push_back(set_name);
+ m_set_reg_nums.resize(m_set_reg_nums.size()+1);
+ lldb::RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return m_sets.size() - 1;
+ }
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+ {
+ reg_collection::const_iterator pos, end = m_regs.end();
+ for (pos = m_regs.begin(); pos != end; ++pos)
+ {
+ if (pos->kinds[kind] == num)
+ return std::distance (m_regs.begin(), pos);
+ }
+
+ return LLDB_INVALID_REGNUM;
+ }
+ void
+ Clear()
+ {
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_reg_names.clear();
+ m_reg_alt_names.clear();
+ m_set_names.clear();
+ }
+
+ void
+ HardcodeARMRegisters();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteRegisterContext can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb::RegisterInfo> reg_collection;
+ typedef std::vector <lldb::RegisterSet> set_collection;
+ typedef std::vector <uint32_t> reg_num_collection;
+ typedef std::vector <reg_num_collection> set_reg_num_collection;
+ typedef std::vector <lldb_private::ConstString> name_collection;
+
+ reg_collection m_regs;
+ set_collection m_sets;
+ set_reg_num_collection m_set_reg_nums;
+ name_collection m_reg_names;
+ name_collection m_reg_alt_names;
+ name_collection m_set_names;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+};
+
+class GDBRemoteRegisterContext : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteRegisterContext (ThreadGDBRemote &thread,
+ lldb_private::StackFrame *frame,
+ GDBRemoteDynamicRegisterInfo ®_info,
+ bool read_all_at_once);
+
+ virtual
+ ~GDBRemoteRegisterContext ();
+
+ //------------------------------------------------------------------
+ // 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);
+
+protected:
+
+ void
+ SetAllRegisterValid (bool b);
+
+ ProcessGDBRemote &
+ GetGDBProcess();
+
+ ThreadGDBRemote &
+ GetGDBThread();
+
+ GDBRemoteDynamicRegisterInfo &m_reg_info;
+ std::vector<bool> m_reg_valid;
+ uint32_t m_reg_valid_stop_id;
+ lldb_private::DataExtractor m_reg_data;
+ bool m_read_all_at_once;
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteRegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext);
+};
+
+#endif // lldb_GDBRemoteRegisterContext_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBServer.cpp b/source/Plugins/Process/gdb-remote/GDBServer.cpp
new file mode 100644
index 0000000..a88ec7b
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBServer.cpp
@@ -0,0 +1,1148 @@
+//===-- GDBServer.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/sysctl.h>
+#include <string>
+#include <vector>
+#include <asl.h>
+
+#include "GDBServerLog.h"
+#include "GDBRemoteSession.h"
+
+using namespace lldb;
+
+//----------------------------------------------------------------------
+// Run loop modes which determine which run loop function will be called
+//----------------------------------------------------------------------
+typedef enum
+{
+ eDCGSRunLoopModeInvalid = 0,
+ eDCGSRunLoopModeGetStartModeFromRemoteProtocol,
+ eDCGSRunLoopModeInferiorAttaching,
+ eDCGSRunLoopModeInferiorLaunching,
+ eDCGSRunLoopModeInferiorExecuting,
+ eDCGSRunLoopModeInferiorKillOrDetach,
+ eDCGSRunLoopModeExit
+} GSRunLoopMode;
+
+typedef enum
+{
+ eLaunchFlavorDefault = 0,
+ eLaunchFlavorPosixSpawn,
+#if defined (__arm__)
+ eLaunchFlavorSpringBoard,
+#endif
+ eLaunchFlavorForkExec,
+} GSLaunchFlavor;
+
+typedef lldb::shared_ptr<GDBRemoteSession> GDBRemoteSP;
+
+typedef struct HandleBroadcastEventInfo
+{
+ TargetSP target_sp;
+ GDBRemoteSP remote_sp;
+ GSRunLoopMode mode;
+
+ Target *
+ GetTarget ()
+ {
+ return target_sp.get();
+ }
+
+ Process *
+ GetProcess()
+ {
+ if (target_sp.get())
+ return target_sp->GetProcess().get();
+ return NULL;
+ }
+
+ GDBRemoteSession *
+ GetRemote ()
+ {
+ return remote_sp.get();
+ }
+
+};
+
+
+//----------------------------------------------------------------------
+// Global Variables
+//----------------------------------------------------------------------
+static int g_lockdown_opt = 0;
+static int g_applist_opt = 0;
+static GSLaunchFlavor g_launch_flavor = eLaunchFlavorDefault;
+int g_isatty = 0;
+
+//----------------------------------------------------------------------
+// Run Loop function prototypes
+//----------------------------------------------------------------------
+void GSRunLoopGetStartModeFromRemote (HandleBroadcastEventInfo *info);
+void GSRunLoopInferiorExecuting (HandleBroadcastEventInfo *info);
+
+
+//----------------------------------------------------------------------
+// Get our program path and arguments from the remote connection.
+// We will need to start up the remote connection without a PID, get the
+// arguments, wait for the new process to finish launching and hit its
+// entry point, and then return the run loop mode that should come next.
+//----------------------------------------------------------------------
+void
+GSRunLoopGetStartModeFromRemote (HandleBroadcastEventInfo *info)
+{
+ std::string packet;
+
+ Target *target = info->GetTarget();
+ GDBRemoteSession *remote = info->GetRemote();
+ if (target != NULL && remote != NULL)
+ {
+ // Spin waiting to get the A packet.
+ while (1)
+ {
+ gdb_err_t err = gdb_err;
+ GDBRemoteSession::PacketEnum type;
+
+ err = remote->HandleReceivedPacket (&type);
+
+ // check if we tried to attach to a process
+ if (type == GDBRemoteSession::vattach || type == GDBRemoteSession::vattachwait)
+ {
+ if (err == gdb_success)
+ {
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+ }
+ else
+ {
+ Log::STDERR ("error: attach failed.");
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+ }
+
+ if (err == gdb_success)
+ {
+ // If we got our arguments we are ready to launch using the arguments
+ // and any environment variables we received.
+ if (type == GDBRemoteSession::set_argv)
+ {
+ info->mode = eDCGSRunLoopModeInferiorLaunching;
+ return;
+ }
+ }
+ else if (err == gdb_not_connected)
+ {
+ Log::STDERR ("error: connection lost.");
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+ else
+ {
+ // a catch all for any other gdb remote packets that failed
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Error getting packet.",__FUNCTION__);
+ continue;
+ }
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s", __FUNCTION__);
+ }
+ }
+ info->mode = eDCGSRunLoopModeExit;
+}
+
+
+//----------------------------------------------------------------------
+// This run loop mode will wait for the process to launch and hit its
+// entry point. It will currently ignore all events except for the
+// process state changed event, where it watches for the process stopped
+// or crash process state.
+//----------------------------------------------------------------------
+GSRunLoopMode
+GSRunLoopLaunchInferior (HandleBroadcastEventInfo *info)
+{
+ // The Process stuff takes a c array, the GSContext has a vector...
+ // So make up a c array.
+ Target *target = info->GetTarget();
+ GDBRemoteSession *remote = info->GetRemote();
+ Process* process = info->GetProcess();
+
+ if (process == NULL)
+ return eDCGSRunLoopModeExit;
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Launching '%s'...", __FUNCTION__, target->GetExecutableModule()->GetFileSpec().GetFilename().AsCString());
+
+ // Our launch type hasn't been set to anything concrete, so we need to
+ // figure our how we are going to launch automatically.
+
+ GSLaunchFlavor launch_flavor = g_launch_flavor;
+ if (launch_flavor == eLaunchFlavorDefault)
+ {
+ // Our default launch method is posix spawn
+ launch_flavor = eLaunchFlavorPosixSpawn;
+
+#if defined (__arm__)
+ // Check if we have an app bundle, if so launch using SpringBoard.
+ if (strstr(inferior_argv[0], ".app"))
+ {
+ launch_flavor = eLaunchFlavorSpringBoard;
+ }
+#endif
+ }
+
+ //ctx.SetLaunchFlavor(launch_flavor);
+
+ const char *stdio_file = NULL;
+ lldb::pid_t pid = process->Launch (remote->GetARGV(), remote->GetENVP(), stdio_file, stdio_file, stdio_file);
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ Log::STDERR ("error: process launch failed: %s", process->GetError().AsCString());
+ }
+ else
+ {
+ if (remote->IsConnected())
+ {
+ // It we are connected already, the next thing gdb will do is ask
+ // whether the launch succeeded, and if not, whether there is an
+ // error code. So we need to fetch one packet from gdb before we wait
+ // on the stop from the target.
+ gdb_err_t err = gdb_err;
+ GDBRemoteSession::PacketEnum type;
+
+ err = remote->HandleReceivedPacket (&type);
+
+ if (err != gdb_success)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Error getting packet.", __FUNCTION__);
+ return eDCGSRunLoopModeExit;
+ }
+ if (type != GDBRemoteSession::query_launch_success)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
+ }
+ }
+ }
+
+ Listener listener("GSRunLoopLaunchInferior");
+ listener.StartListeningForEvents (process, Process::eBroadcastBitStateChanged);
+ while (process->GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ uint32_t event_mask = 0;
+ while (listener.WaitForEvent(NULL, &event_mask))
+ {
+ if (event_mask & Process::eBroadcastBitStateChanged)
+ {
+ Event event;
+ StateType event_state;
+ while ((event_state = process->GetNextEvent (&event)))
+ if (StateIsStoppedState(event_state))
+ {
+ GDBServerLog::LogIf (GS_LOG_EVENTS, "%s process %4.4x stopped with state %s", __FUNCTION__, pid, StateAsCString(event_state));
+
+ switch (event_state)
+ {
+ default:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateSuspended:
+ break; // Ignore
+
+ case eStateRunning:
+ case eStateStepping:
+ // Still waiting to stop at entry point...
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ return eDCGSRunLoopModeInferiorExecuting;
+
+ case eStateDetached:
+ case eStateExited:
+ pid = LLDB_INVALID_PROCESS_ID;
+ return eDCGSRunLoopModeExit;
+ }
+ }
+
+ if (event_state = eStateInvalid)
+ break;
+ }
+ }
+ }
+
+ return eDCGSRunLoopModeExit;
+}
+
+
+//----------------------------------------------------------------------
+// This run loop mode will wait for the process to launch and hit its
+// entry point. It will currently ignore all events except for the
+// process state changed event, where it watches for the process stopped
+// or crash process state.
+//----------------------------------------------------------------------
+GSRunLoopMode
+GSRunLoopLaunchAttaching (HandleBroadcastEventInfo *info, lldb::pid_t& pid)
+{
+ Process* process = info->GetProcess();
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, pid);
+ pid = process->Attach(pid);
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return eDCGSRunLoopModeExit;
+ return eDCGSRunLoopModeInferiorExecuting;
+}
+
+//----------------------------------------------------------------------
+// Watch for signals:
+// SIGINT: so we can halt our inferior. (disabled for now)
+// SIGPIPE: in case our child process dies
+//----------------------------------------------------------------------
+lldb::pid_t g_pid;
+int g_sigpipe_received = 0;
+void
+signal_handler(int signo)
+{
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (%s)", __FUNCTION__, Host::GetSignalAsCString(signo));
+
+ switch (signo)
+ {
+// case SIGINT:
+// DNBProcessKill (g_pid, signo);
+// break;
+
+ case SIGPIPE:
+ g_sigpipe_received = 1;
+ break;
+ }
+}
+
+// Return the new run loop mode based off of the current process state
+void
+HandleProcessStateChange (HandleBroadcastEventInfo *info, bool initialize)
+{
+ Process *process = info->GetProcess();
+ if (process == NULL)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+
+ if (process->GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+ StateType pid_state = process->GetState ();
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (info, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, StateAsCString(pid_state));
+
+ switch (pid_state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ // Something bad happened
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+
+ case eStateAttaching:
+ case eStateLaunching:
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+
+ case eStateSuspended:
+ case eStateCrashed:
+ case eStateStopped:
+ if (initialize == false)
+ {
+ // Compare the last stop count to our current notion of a stop count
+ // to make sure we don't notify more than once for a given stop.
+ static uint32_t g_prev_stop_id = 0;
+ uint32_t stop_id = process->GetStopID();
+ bool pid_stop_count_changed = g_prev_stop_id != stop_id;
+ if (pid_stop_count_changed)
+ {
+ info->GetRemote()->FlushSTDIO();
+
+ if (stop_id == 1)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id);
+ }
+ else
+ {
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id);
+ info->GetRemote()->NotifyThatProcessStopped ();
+ }
+ }
+ else
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id);
+ }
+ }
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+
+ case eStateStepping:
+ case eStateRunning:
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+
+ case eStateExited:
+ info->GetRemote()->HandlePacket_last_signal (NULL);
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+
+ }
+
+ // Catch all...
+ info->mode = eDCGSRunLoopModeExit;
+}
+
+bool
+CommunicationHandleBroadcastEvent (Broadcaster *broadcaster, uint32_t event_mask, void *baton)
+{
+ HandleBroadcastEventInfo *info = (HandleBroadcastEventInfo *)baton;
+ Process *process = info->GetProcess();
+
+ if (process == NULL)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ return true;
+ }
+
+ if (event_mask & Communication::eBroadcastBitPacketAvailable)
+ {
+ if (process->IsRunning())
+ {
+ if (info->GetRemote()->HandleAsyncPacket() == gdb_not_connected)
+ info->mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ if (info->GetRemote()->HandleReceivedPacket() == gdb_not_connected)
+ info->mode = eDCGSRunLoopModeExit;
+ }
+ }
+ if (event_mask & Communication::eBroadcastBitReadThreadDidExit)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ }
+ if (event_mask & Communication::eBroadcastBitDisconnected)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ }
+
+ return true;
+
+}
+
+bool
+ProcessHandleBroadcastEvent (Broadcaster *broadcaster, uint32_t event_mask, void *baton)
+{
+ HandleBroadcastEventInfo *info = (HandleBroadcastEventInfo *)baton;
+ Process *process = info->GetProcess();
+ if (process == NULL)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ return true;
+ }
+
+ if (event_mask & Process::eBroadcastBitStateChanged)
+ {
+ // Consume all available process events with no timeout
+ Event event;
+ StateType process_state;
+ while ((process_state = process->GetNextEvent (&event)) != eStateInvalid)
+ {
+ if (StateIsStoppedState(process_state))
+ info->GetRemote()->FlushSTDIO();
+ HandleProcessStateChange (info, false);
+
+ if (info->mode != eDCGSRunLoopModeInferiorExecuting)
+ break;
+ }
+ }
+ else
+ if (event_mask & (Process::eBroadcastBitSTDOUT | Process::eBroadcastBitSTDERR))
+ {
+ info->GetRemote()->FlushSTDIO();
+ }
+ return true;
+}
+
+// This function handles the case where our inferior program is stopped and
+// we are waiting for gdb remote protocol packets. When a packet occurs that
+// makes the inferior run, we need to leave this function with a new state
+// as the return code.
+void
+GSRunLoopInferiorExecuting (HandleBroadcastEventInfo *info)
+{
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s", __FUNCTION__);
+
+ // Init our mode and set 'is_running' based on the current process state
+ HandleProcessStateChange (info, true);
+
+ uint32_t desired_mask, acquired_mask;
+ Listener listener("GSRunLoopInferiorExecuting");
+
+ desired_mask = Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit |
+ Communication::eBroadcastBitDisconnected;
+
+ acquired_mask = listener.StartListeningForEvents (&(info->GetRemote()->GetPacketComm()),
+ desired_mask,
+ CommunicationHandleBroadcastEvent,
+ info);
+
+ assert (acquired_mask == desired_mask);
+ desired_mask = GDBRemotePacket::eBroadcastBitPacketAvailable;
+
+ acquired_mask = listener.StartListeningForEvents (&(info->GetRemote()->GetPacketComm()),
+ desired_mask,
+ CommunicationHandleBroadcastEvent,
+ info);
+
+ assert (acquired_mask == desired_mask);
+
+ desired_mask = Process::eBroadcastBitStateChanged |
+ Process::eBroadcastBitSTDOUT |
+ Process::eBroadcastBitSTDERR ;
+ acquired_mask = listener.StartListeningForEvents (info->GetProcess (),
+ desired_mask,
+ ProcessHandleBroadcastEvent,
+ info);
+
+ assert (acquired_mask == desired_mask);
+
+ Process *process = info->GetProcess();
+
+ while (process->IsAlive())
+ {
+ if (!info->GetRemote()->IsConnected())
+ {
+ info->mode = eDCGSRunLoopModeInferiorKillOrDetach;
+ break;
+ }
+
+ // We want to make sure we consume all process state changes and have
+ // whomever is notifying us to wait for us to reset the event bit before
+ // continuing.
+ //ctx.Events().SetResetAckMask (GSContext::event_proc_state_changed);
+ uint32_t event_mask = 0;
+ Broadcaster *broadcaster = listener.WaitForEvent(NULL, &event_mask);
+ if (broadcaster)
+ {
+ listener.HandleBroadcastEvent(broadcaster, event_mask);
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Convenience function to set up the remote listening port
+// Returns 1 for success 0 for failure.
+//----------------------------------------------------------------------
+
+static bool
+StartListening (HandleBroadcastEventInfo *info, int listen_port)
+{
+ if (!info->GetRemote()->IsConnected())
+ {
+ Log::STDOUT ("Listening to port %i...\n", listen_port);
+ char connect_url[256];
+ snprintf(connect_url, sizeof(connect_url), "listen://%i", listen_port);
+
+ Communication &comm = info->remote_sp->GetPacketComm();
+ comm.SetConnection (new ConnectionFileDescriptor);
+
+ if (comm.Connect (connect_url))
+ {
+ if (comm.StartReadThread())
+ return true;
+
+ Log::STDERR ("Failed to start the communication read thread.\n", connect_url);
+ comm.Disconnect();
+ }
+ else
+ {
+ Log::STDERR ("Failed to connection to %s.\n", connect_url);
+ }
+ return false;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------
+// ASL Logging callback that can be registered with DNBLogSetLogDCScriptInterpreter::Type
+//----------------------------------------------------------------------
+//void
+//ASLLogDCScriptInterpreter::Type(void *baton, uint32_t flags, const char *format, va_list args)
+//{
+// if (format == NULL)
+// return;
+// static aslmsg g_aslmsg = NULL;
+// if (g_aslmsg == NULL)
+// {
+// g_aslmsg = ::asl_new (ASL_TYPE_MSG);
+// char asl_key_sender[PATH_MAX];
+// snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.dc-gdbserver-%g", dc_gdbserverVersionNumber);
+// ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
+// }
+//
+// int asl_level;
+// if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT;
+// else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR;
+// else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
+// else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
+// else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
+//
+// ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
+//}
+
+//----------------------------------------------------------------------
+// FILE based Logging callback that can be registered with
+// DNBLogSetLogDCScriptInterpreter::Type
+//----------------------------------------------------------------------
+void
+FileLogDCScriptInterpreter::Type(void *baton, uint32_t flags, const char *format, va_list args)
+{
+ if (baton == NULL || format == NULL)
+ return;
+
+ ::vfprintf ((FILE *)baton, format, args);
+ ::fprintf ((FILE *)baton, "\n");
+}
+
+//----------------------------------------------------------------------
+// option descriptors for getopt_long()
+//----------------------------------------------------------------------
+static struct option g_long_options[] =
+{
+ { "arch", required_argument, NULL, 'c' },
+ { "attach", required_argument, NULL, 'a' },
+ { "debug", no_argument, NULL, 'g' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
+ { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
+ { "log-file", required_argument, NULL, 'l' },
+ { "log-flags", required_argument, NULL, 'f' },
+ { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
+ { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose namet starts with ARG
+ { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
+ { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
+ { NULL, 0, NULL, 0 }
+};
+
+extern const double dc_gdbserverVersionNumber;
+int
+main (int argc, char *argv[])
+{
+ Initialize();
+ Host::ThreadCreated ("[main]");
+
+ g_isatty = ::isatty (STDIN_FILENO);
+
+// signal (SIGINT, signal_handler);
+ signal (SIGPIPE, signal_handler);
+
+ Log *log = GDBServerLog::GetLogIfAllCategoriesSet(GS_LOG_ALL);
+ const char *this_exe_name = argv[0];
+ int i;
+ int attach_pid = LLDB_INVALID_PROCESS_ID;
+ for (i=0; i<argc; i++)
+ GDBServerLog::LogIf(GS_LOG_DEBUG, "argv[%i] = %s", i, argv[i]);
+
+ FILE* log_file = NULL;
+ uint32_t log_flags = 0;
+ // Parse our options
+ int ch;
+ int long_option_index = 0;
+ int debug = 0;
+ std::string waitfor_pid_name; // Wait for a process that starts with this name
+ std::string attach_pid_name;
+ useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
+ useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever.
+ ArchSpec arch;
+ GSRunLoopMode start_mode = eDCGSRunLoopModeExit;
+
+ while ((ch = getopt_long(argc, argv, "a:c:d:gi:vktl:f:w:x:", g_long_options, &long_option_index)) != -1)
+ {
+// DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
+// ch, (uint8_t)ch,
+// g_long_options[long_option_index].name,
+// g_long_options[long_option_index].has_arg ? '=' : ' ',
+// optarg ? optarg : "");
+ switch (ch)
+ {
+ case 0: // Any optional that auto set themselves will return 0
+ break;
+
+ case 'c':
+ arch.SetArch(optarg);
+ if (!arch.IsValid())
+ {
+ Log::STDERR ("error: invalid arch string '%s'\n", optarg);
+ exit (8);
+ }
+ break;
+
+ case 'a':
+ if (optarg && optarg[0])
+ {
+ if (isdigit(optarg[0]))
+ {
+ char *end = NULL;
+ attach_pid = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ Log::STDERR ("error: invalid pid option '%s'\n", optarg);
+ exit (4);
+ }
+ }
+ else
+ {
+ attach_pid_name = optarg;
+ }
+ start_mode = eDCGSRunLoopModeInferiorAttaching;
+ }
+ break;
+
+ // --waitfor=NAME
+ case 'w':
+ if (optarg && optarg[0])
+ {
+ waitfor_pid_name = optarg;
+ start_mode = eDCGSRunLoopModeInferiorAttaching;
+ }
+ break;
+
+ // --waitfor-interval=USEC
+ case 'i':
+ if (optarg && optarg[0])
+ {
+ char *end = NULL;
+ waitfor_interval = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ Log::STDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
+ exit (6);
+ }
+ }
+ break;
+
+ // --waitfor-duration=SEC
+ case 'd':
+ if (optarg && optarg[0])
+ {
+ char *end = NULL;
+ waitfor_duration = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ Log::STDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
+ exit (7);
+ }
+ }
+ break;
+
+ case 'x':
+ if (optarg && optarg[0])
+ {
+ if (strcasecmp(optarg, "auto") == 0)
+ g_launch_flavor = eLaunchFlavorDefault;
+ else if (strcasestr(optarg, "posix") == optarg)
+ g_launch_flavor = eLaunchFlavorPosixSpawn;
+ else if (strcasestr(optarg, "fork") == optarg)
+ g_launch_flavor = eLaunchFlavorForkExec;
+#if defined (__arm__)
+ else if (strcasestr(optarg, "spring") == optarg)
+ g_launch_flavor = eLaunchFlavorSpringBoard;
+#endif
+ else
+ {
+ Log::STDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
+ Log::STDERR ("Valid values TYPE are:\n");
+ Log::STDERR (" auto Auto-detect the best launch method to use.\n");
+ Log::STDERR (" posix Launch the executable using posix_spawn.\n");
+ Log::STDERR (" fork Launch the executable using fork and exec.\n");
+#if defined (__arm__)
+ Log::STDERR (" spring Launch the executable through Springboard.\n");
+#endif
+ exit (5);
+ }
+ }
+ break;
+
+ case 'l': // Set Log File
+ if (optarg && optarg[0])
+ {
+ if (strcasecmp(optarg, "stdout") == 0)
+ log_file = stdout;
+ else if (strcasecmp(optarg, "stderr") == 0)
+ log_file = stderr;
+ else
+ log_file = fopen(optarg, "w+");
+
+ if (log_file == NULL)
+ {
+ const char *errno_str = strerror(errno);
+ Log::STDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
+ }
+ }
+ break;
+
+ case 'f': // Log Flags
+ if (optarg && optarg[0])
+ log_flags = strtoul(optarg, NULL, 0);
+ break;
+
+ case 'g':
+ debug = 1;
+ //DNBLogSetDebug(1);
+ break;
+
+ case 't':
+ g_applist_opt = 1;
+ break;
+
+ case 'k':
+ g_lockdown_opt = 1;
+ break;
+
+ case 'v':
+ //DNBLogSetVerbose(1);
+ break;
+ }
+ }
+
+ // Skip any options we consumed with getopt_long
+ argc -= optind;
+ argv += optind;
+
+ // It is ok for us to set NULL as the logfile (this will disable any logging)
+
+// if (log_file != NULL)
+// {
+// DNBLogSetLogDCScriptInterpreter::Type(FileLogDCScriptInterpreter::Type, log_file);
+// // If our log file was set, yet we have no log flags, log everything!
+// if (log_flags == 0)
+// log_flags = LOG_ALL | LOG_DCGS_ALL;
+//
+// DNBLogSetLogMask (log_flags);
+// }
+// else
+// {
+// // Enable DNB logging
+// DNBLogSetLogDCScriptInterpreter::Type(ASLLogDCScriptInterpreter::Type, NULL);
+// DNBLogSetLogMask (log_flags);
+//
+// }
+
+ // as long as we're dropping remotenub in as a replacement for gdbserver,
+ // explicitly note that this is not gdbserver.
+
+ Log::STDOUT ("debugserver-%g \n", dc_gdbserverVersionNumber);
+ int listen_port = -1;
+ if (g_lockdown_opt == 0 && g_applist_opt == 0)
+ {
+ // Make sure we at least have port
+ if (argc < 1)
+ {
+ Log::STDERR ("Usage: %s host:port [program-name program-arg1 program-arg2 ...]\n", this_exe_name);
+ exit (1);
+ }
+ // accept 'localhost:' prefix on port number
+
+ std::string host_str;
+ std::string port_str(argv[0]);
+
+ // We just used the host:port arg...
+ argc--;
+ argv++;
+
+ size_t port_idx = port_str.find(':');
+ if (port_idx != std::string::npos)
+ {
+ host_str.assign(port_str, 0, port_idx);
+ port_str.erase(0, port_idx + 1);
+ }
+
+ if (port_str.empty())
+ {
+ Log::STDERR ("error: no port specified\nUsage: %s host:port [program-name program-arg1 program-arg2 ...]\n", this_exe_name);
+ exit (2);
+ }
+ else if (port_str.find_first_not_of("0123456789") != std::string::npos)
+ {
+ Log::STDERR ("error: port must be an integer: %s\nUsage: %s host:port [program-name program-arg1 program-arg2 ...]\n", port_str.c_str(), this_exe_name);
+ exit (3);
+ }
+ //DNBLogDebug("host_str = '%s' port_str = '%s'", host_str.c_str(), port_str.c_str());
+ listen_port = atoi (port_str.c_str());
+ }
+
+
+ // We must set up some communications now.
+
+ FileSpec exe_spec;
+ if (argv[0])
+ exe_spec.SetFile (argv[0]);
+
+ HandleBroadcastEventInfo info;
+ info.target_sp = TargetList::SharedList().CreateTarget(&exe_spec, &arch);
+ ProcessSP process_sp (info.target_sp->CreateProcess ());
+ info.remote_sp.reset (new GDBRemoteSession (process_sp));
+
+ info.remote_sp->SetLog (log);
+ StreamString sstr;
+ sstr.Printf("ConnectionFileDescriptor(%s)", argv[0]);
+
+ if (info.remote_sp.get() == NULL)
+ {
+ Log::STDERR ("error: failed to create a GDBRemoteSession class\n");
+ return -1;
+ }
+
+
+
+ // If we know we're waiting to attach, we don't need any of this other info.
+ if (start_mode != eDCGSRunLoopModeInferiorAttaching)
+ {
+ if (argc == 0 || g_lockdown_opt)
+ {
+ if (g_lockdown_opt != 0)
+ {
+ // Work around for SIGPIPE crashes due to posix_spawn issue. We have to close
+ // STDOUT and STDERR, else the first time we try and do any, we get SIGPIPE and
+ // die as posix_spawn is doing bad things with our file descriptors at the moment.
+ int null = open("/dev/null", O_RDWR);
+ dup2(null, STDOUT_FILENO);
+ dup2(null, STDERR_FILENO);
+ }
+ else if (g_applist_opt != 0)
+ {
+// // List all applications we are able to see
+// std::string applist_plist;
+// int err = ListApplications(applist_plist, false, false);
+// if (err == 0)
+// {
+// fputs (applist_plist.c_str(), stdout);
+// }
+// else
+// {
+// Log::STDERR ("error: ListApplications returned error %i\n", err);
+// }
+// // Exit with appropriate error if we were asked to list the applications
+// // with no other args were given (and we weren't trying to do this over
+// // lockdown)
+// return err;
+ return 0;
+ }
+
+ //DNBLogDebug("Get args from remote protocol...");
+ start_mode = eDCGSRunLoopModeGetStartModeFromRemoteProtocol;
+ }
+ else
+ {
+ start_mode = eDCGSRunLoopModeInferiorLaunching;
+ // Fill in the argv array in the context from the rest of our args.
+ // Skip the name of this executable and the port number
+ info.remote_sp->SetArguments (argc, argv);
+ }
+ }
+
+ if (start_mode == eDCGSRunLoopModeExit)
+ return -1;
+
+ info.mode = start_mode;
+
+ while (info.mode != eDCGSRunLoopModeExit)
+ {
+ switch (info.mode)
+ {
+ case eDCGSRunLoopModeGetStartModeFromRemoteProtocol:
+ #if defined (__arm__)
+ if (g_lockdown_opt)
+ {
+ if (!info.remote_sp->GetCommunication()->IsConnected())
+ {
+ if (info.remote_sp->GetCommunication()->ConnectToService () != gdb_success)
+ {
+ Log::STDERR ("Failed to get connection from a remote gdb process.\n");
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else if (g_applist_opt != 0)
+ {
+ // List all applications we are able to see
+ std::string applist_plist;
+ if (ListApplications(applist_plist, false, false) == 0)
+ {
+ //DNBLogDebug("Task list: %s", applist_plist.c_str());
+
+ info.remote_sp->GetCommunication()->Write(applist_plist.c_str(), applist_plist.size());
+ // Issue a read that will never yield any data until the other side
+ // closes the socket so this process doesn't just exit and cause the
+ // socket to close prematurely on the other end and cause data loss.
+ std::string buf;
+ info.remote_sp->GetCommunication()->Read(buf);
+ }
+ info.remote_sp->GetCommunication()->Disconnect(false);
+ info.mode = eDCGSRunLoopModeExit;
+ break;
+ }
+ else
+ {
+ // Start watching for remote packets
+ info.remote_sp->StartReadRemoteDataThread();
+ }
+ }
+ }
+ else
+#endif
+ {
+ if (StartListening (&info, listen_port))
+ Log::STDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
+ else
+ info.mode = eDCGSRunLoopModeExit;
+ }
+
+ if (info.mode != eDCGSRunLoopModeExit)
+ GSRunLoopGetStartModeFromRemote (&info);
+ break;
+
+ case eDCGSRunLoopModeInferiorAttaching:
+ if (!waitfor_pid_name.empty())
+ {
+ // Set our end wait time if we are using a waitfor-duration
+ // option that may have been specified
+
+ TimeValue attach_timeout_abstime;
+ if (waitfor_duration != 0)
+ {
+ attach_timeout_abstime = TimeValue::Now();
+ attach_timeout_abstime.OffsetWithSeconds (waitfor_duration);
+ }
+ GSLaunchFlavor launch_flavor = g_launch_flavor;
+ if (launch_flavor == eLaunchFlavorDefault)
+ {
+ // Our default launch method is posix spawn
+ launch_flavor = eLaunchFlavorPosixSpawn;
+
+#if defined (__arm__)
+ // Check if we have an app bundle, if so launch using SpringBoard.
+ if (waitfor_pid_name.find (".app") != std::string::npos)
+ {
+ launch_flavor = eLaunchFlavorSpringBoard;
+ }
+#endif
+ }
+
+ //ctx.SetLaunchFlavor(launch_flavor);
+
+
+ lldb::pid_t pid = info.GetProcess()->Attach (waitfor_pid_name.c_str());
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ info.GetRemote()->GetLaunchError() = info.GetProcess()->GetError();
+ Log::STDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), info.GetRemote()->GetLaunchError().AsCString());
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ info.mode = eDCGSRunLoopModeInferiorExecuting;
+ }
+ }
+ else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ Log::STDOUT ("Attaching to process %i...\n", attach_pid);
+ info.mode = GSRunLoopLaunchAttaching (&info, attach_pid);
+ if (info.mode != eDCGSRunLoopModeInferiorExecuting)
+ {
+ const char *error_str = info.GetRemote()->GetLaunchError().AsCString();
+ Log::STDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ }
+ else if (!attach_pid_name.empty ())
+ {
+ lldb::pid_t pid = info.GetProcess()->Attach (waitfor_pid_name.c_str());
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ info.GetRemote()->GetLaunchError() = info.GetProcess()->GetError();
+ Log::STDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), info.GetRemote()->GetLaunchError().AsCString());
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ info.mode = eDCGSRunLoopModeInferiorExecuting;
+ }
+ }
+ else
+ {
+ Log::STDERR ("error: asked to attach with empty name and invalid PID.");
+ info.mode = eDCGSRunLoopModeExit;
+ }
+
+ if (info.mode != eDCGSRunLoopModeExit)
+ {
+ if (StartListening (&info, listen_port))
+ Log::STDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
+ else
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ break;
+
+ case eDCGSRunLoopModeInferiorLaunching:
+ info.mode = GSRunLoopLaunchInferior (&info);
+
+ if (info.mode == eDCGSRunLoopModeInferiorExecuting)
+ {
+ if (StartListening (&info, listen_port))
+ Log::STDOUT ("Got a connection, waiting for debugger instructions for task \"%s\".\n", argv[0]);
+ else
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ Log::STDERR ("error: failed to launch process %s: %s\n", argv[0], info.GetRemote()->GetLaunchError().AsCString());
+ }
+ break;
+
+ case eDCGSRunLoopModeInferiorExecuting:
+ GSRunLoopInferiorExecuting (&info);
+ break;
+
+ case eDCGSRunLoopModeInferiorKillOrDetach:
+ {
+ Process *process = info.GetProcess();
+ if (process && process->IsAlive())
+ {
+ process->Kill(SIGCONT);
+ process->Kill(SIGKILL);
+ }
+ }
+ info.mode = eDCGSRunLoopModeExit;
+ break;
+
+ default:
+ info.mode = eDCGSRunLoopModeExit;
+ case eDCGSRunLoopModeExit:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBServerLog.cpp b/source/Plugins/Process/gdb-remote/GDBServerLog.cpp
new file mode 100644
index 0000000..2d4116e
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBServerLog.cpp
@@ -0,0 +1,80 @@
+//===-- GDBServerLog.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// GDBServerLog.cpp
+// liblldb
+//
+// Created by Greg Clayton on 6/19/09.
+//
+//
+//----------------------------------------------------------------------
+
+#include "GDBServerLog.h"
+
+using namespace lldb;
+
+static Log *
+LogAccessor (bool get, Log *log)
+{
+ static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+ if (get)
+ {
+// // Debug code below for enabling logging by default
+// if (g_log == NULL)
+// {
+// g_log = new Log("/dev/stdout", false);
+// g_log->GetMask().SetAllFlagBits(GS_LOG_ALL);
+// g_log->GetOptions().Set(LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_THREAD_NAME);
+// }
+ }
+ else
+ {
+ if (g_log)
+ delete g_log;
+ g_log = log;
+ }
+
+ return g_log;
+}
+
+Log *
+GDBServerLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = LogAccessor (true, NULL);
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+GDBServerLog::SetLog (Log *log)
+{
+ LogAccessor (false, log);
+}
+
+
+void
+GDBServerLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log = GDBServerLog::GetLogIfAllCategoriesSet (mask);
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBServerLog.h b/source/Plugins/Process/gdb-remote/GDBServerLog.h
new file mode 100644
index 0000000..3dec808
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBServerLog.h
@@ -0,0 +1,55 @@
+//===-- GDBServerLog.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// GDBServerLog.h
+// liblldb
+//
+// Created by Greg Clayton on 6/19/09.
+//
+//
+//----------------------------------------------------------------------
+
+#ifndef liblldb_GDBServerLog_h_
+#define liblldb_GDBServerLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+#include "lldb/Core/Log.h"
+
+// Project includes
+#define GS_LOG_VERBOSE (1u << 0)
+#define GS_LOG_DEBUG (1u << 1)
+#define GS_LOG_PACKETS (1u << 2)
+#define GS_LOG_EVENTS (1u << 3)
+#define GS_LOG_MINIMAL (1u << 4)
+#define GS_LOG_ALL (UINT32_MAX)
+#define GS_LOG_DEFAULT (GS_LOG_VERBOSE |\
+ GS_LOG_PACKETS)
+
+namespace lldb {
+
+class GDBServerLog
+{
+public:
+ static Log *
+ GetLog (uint32_t mask = 0);
+
+ static void
+ SetLog (Log *log);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+} // namespace lldb
+
+#endif // liblldb_GDBServerLog_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
new file mode 100644
index 0000000..e08679c
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -0,0 +1,2272 @@
+//===-- ProcessGDBRemote.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
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach-o/dyld.h>
+#include <spawn.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <algorithm>
+#include <map>
+
+// Other libraries and framework includes
+
+#include "lldb/Breakpoint/WatchpointLocation.h"
+#include "lldb/Core/Args.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "PseudoTerminal.h"
+
+// Project includes
+#include "lldb/Host/Host.h"
+#include "StringExtractorGDBRemote.h"
+#include "GDBRemoteRegisterContext.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+#include "libunwind.h"
+#include "MacOSXLibunwindCallbacks.h"
+
+#if defined (__i386__) || defined (__x86_64__)
+#define MACH_EXC_DATA0_SOFTWARE_BREAKPOINT EXC_I386_BPT
+#define MACH_EXC_DATA0_TRACE EXC_I386_SGL
+#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+#define MACH_EXC_DATA0_SOFTWARE_BREAKPOINT EXC_PPC_BREAKPOINT
+#elif defined (__arm__)
+#define MACH_EXC_DATA0_SOFTWARE_BREAKPOINT EXC_ARM_BREAKPOINT
+#endif
+
+
+#define DEBUGSERVER_BASENAME "debugserver"
+using namespace lldb;
+using namespace lldb_private;
+
+static inline uint16_t
+get_random_port ()
+{
+ return (arc4random() % (UINT16_MAX - 1000u)) + 1000u;
+}
+
+
+const char *
+ProcessGDBRemote::GetPluginNameStatic()
+{
+ return "process.gdb-remote";
+}
+
+const char *
+ProcessGDBRemote::GetPluginDescriptionStatic()
+{
+ return "GDB Remote protocol based debugging plug-in.";
+}
+
+void
+ProcessGDBRemote::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance);
+}
+
+
+Process*
+ProcessGDBRemote::CreateInstance (Target &target, Listener &listener)
+{
+ return new ProcessGDBRemote (target, listener);
+}
+
+bool
+ProcessGDBRemote::CanDebug(Target &target)
+{
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target.GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessGDBRemote constructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
+ Process (target, listener),
+ m_dynamic_loader_ap (),
+ m_byte_order (eByteOrderHost),
+ m_flags (0),
+ m_stdio_communication ("gdb-remote.stdio"),
+ m_stdio_mutex (Mutex::eMutexTypeRecursive),
+ m_stdout_data (),
+ m_arch_spec (),
+ m_gdb_comm(),
+ m_debugserver_pid (LLDB_INVALID_PROCESS_ID),
+ m_debugserver_monitor (0),
+ m_register_info (),
+ m_curr_tid (LLDB_INVALID_THREAD_ID),
+ m_curr_tid_run (LLDB_INVALID_THREAD_ID),
+ m_async_broadcaster ("lldb.process.gdb-remote.async-broadcaster"),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ m_z0_supported (1),
+ m_continue_packet(),
+ m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_libunwind_target_type (UNW_TARGET_UNSPECIFIED),
+ m_libunwind_addr_space (NULL),
+ m_waiting_for_attach (false),
+ m_packet_timeout (1),
+ m_max_memory_size (512)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::~ProcessGDBRemote()
+{
+ // m_mach_process.UnregisterNotificationCallbacks (this);
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+const char *
+ProcessGDBRemote::GetPluginName()
+{
+ return "Process debugging plug-in that uses the GDB remote protocol";
+}
+
+const char *
+ProcessGDBRemote::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessGDBRemote::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessGDBRemote::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+ strm->Printf("TODO: fill this in\n");
+}
+
+Error
+ProcessGDBRemote::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in commands are currently supported.");
+ return error;
+}
+
+Log *
+ProcessGDBRemote::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+void
+ProcessGDBRemote::BuildDynamicRegisterInfo ()
+{
+ char register_info_command[64];
+ m_register_info.Clear();
+ StringExtractorGDBRemote::Type packet_type = StringExtractorGDBRemote::eResponse;
+ uint32_t reg_offset = 0;
+ uint32_t reg_num = 0;
+ for (; packet_type == StringExtractorGDBRemote::eResponse; ++reg_num)
+ {
+ ::snprintf (register_info_command, sizeof(register_info_command), "qRegisterInfo%x", reg_num);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(register_info_command, response, 2, false))
+ {
+ packet_type = response.GetType();
+ if (packet_type == StringExtractorGDBRemote::eResponse)
+ {
+ std::string name;
+ std::string value;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ reg_num, // native register number
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ reg_num // GDB reg num
+ }
+ };
+
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("name") == 0)
+ {
+ reg_name.SetCString(value.c_str());
+ }
+ else if (name.compare("alt-name") == 0)
+ {
+ alt_name.SetCString(value.c_str());
+ }
+ else if (name.compare("bitsize") == 0)
+ {
+ reg_info.byte_size = Args::StringToUInt32(value.c_str(), 0, 0) / CHAR_BIT;
+ }
+ else if (name.compare("offset") == 0)
+ {
+ uint32_t offset = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0);
+ if (offset != offset)
+ {
+ reg_offset = offset;
+ reg_info.byte_offset = offset;
+ }
+ }
+ else if (name.compare("encoding") == 0)
+ {
+ if (value.compare("uint") == 0)
+ reg_info.encoding = eEncodingUint;
+ else if (value.compare("sint") == 0)
+ reg_info.encoding = eEncodingSint;
+ else if (value.compare("ieee754") == 0)
+ reg_info.encoding = eEncodingIEEE754;
+ else if (value.compare("vector") == 0)
+ reg_info.encoding = eEncodingVector;
+ }
+ else if (name.compare("format") == 0)
+ {
+ if (value.compare("binary") == 0)
+ reg_info.format = eFormatBinary;
+ else if (value.compare("decimal") == 0)
+ reg_info.format = eFormatDecimal;
+ else if (value.compare("hex") == 0)
+ reg_info.format = eFormatHex;
+ else if (value.compare("float") == 0)
+ reg_info.format = eFormatFloat;
+ else if (value.compare("vector-sint8") == 0)
+ reg_info.format = eFormatVectorOfSInt8;
+ else if (value.compare("vector-uint8") == 0)
+ reg_info.format = eFormatVectorOfUInt8;
+ else if (value.compare("vector-sint16") == 0)
+ reg_info.format = eFormatVectorOfSInt16;
+ else if (value.compare("vector-uint16") == 0)
+ reg_info.format = eFormatVectorOfUInt16;
+ else if (value.compare("vector-sint32") == 0)
+ reg_info.format = eFormatVectorOfSInt32;
+ else if (value.compare("vector-uint32") == 0)
+ reg_info.format = eFormatVectorOfUInt32;
+ else if (value.compare("vector-float32") == 0)
+ reg_info.format = eFormatVectorOfFloat32;
+ else if (value.compare("vector-uint128") == 0)
+ reg_info.format = eFormatVectorOfUInt128;
+ }
+ else if (name.compare("set") == 0)
+ {
+ set_name.SetCString(value.c_str());
+ }
+ else if (name.compare("gcc") == 0)
+ {
+ reg_info.kinds[eRegisterKindGCC] = Args::StringToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("dwarf") == 0)
+ {
+ reg_info.kinds[eRegisterKindDWARF] = Args::StringToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("generic") == 0)
+ {
+ if (value.compare("pc") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if (value.compare("sp") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if (value.compare("fp") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if (value.compare("ra") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+ else if (value.compare("flags") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ }
+
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ }
+ }
+ else
+ {
+ packet_type = StringExtractorGDBRemote::eError;
+ }
+ }
+
+ if (reg_num == 0)
+ {
+ // We didn't get anything. See if we are debugging ARM and fill with
+ // a hard coded register set until we can get an updated debugserver
+ // down on the devices.
+ ArchSpec arm_arch ("arm");
+ if (GetTarget().GetArchitecture() == arm_arch)
+ m_register_info.HardcodeARMRegisters();
+ }
+ m_register_info.Finalize ();
+}
+
+Error
+ProcessGDBRemote::WillLaunch (Module* module)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttach (lldb::pid_t pid)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttach (const char *process_name, bool wait_for_launch)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillLaunchOrAttach ()
+{
+ Error error;
+ // TODO: this is hardcoded for macosx right now. We need this to be more dynamic
+ m_dynamic_loader_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.macosx-dyld"));
+
+ if (m_dynamic_loader_ap.get() == NULL)
+ error.SetErrorString("unable to find the dynamic loader named 'dynamic-loader.macosx-dyld'");
+ m_stdio_communication.Clear ();
+
+ return error;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessGDBRemote::DoLaunch
+(
+ Module* module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+ // ::LogSetBitMask (GDBR_LOG_DEFAULT);
+ // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+ // ::LogSetLogFile ("/dev/stdout");
+ Error error;
+
+ ObjectFile * object_file = module->GetObjectFile();
+ if (object_file)
+ {
+ ArchSpec inferior_arch(module->GetArchitecture());
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+
+ bool start_debugserver_with_inferior_args = false;
+ if (start_debugserver_with_inferior_args)
+ {
+ // We want to launch debugserver with the inferior program and its
+ // arguments on the command line. We should only do this if we
+ // the GDB server we are talking to doesn't support the 'A' packet.
+ error = StartDebugserverProcess (host_port,
+ argv,
+ envp,
+ NULL, //stdin_path,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ inferior_arch);
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver (host_port);
+ if (error.Success())
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID (m_packet_timeout));
+ }
+ }
+ else
+ {
+ error = StartDebugserverProcess (host_port,
+ NULL,
+ NULL,
+ NULL, //stdin_path,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ inferior_arch);
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver (host_port);
+ if (error.Success())
+ {
+ // Send the environment and the program + arguments after we connect
+ if (envp)
+ {
+ const char *env_entry;
+ for (int i=0; (env_entry = envp[i]); ++i)
+ {
+ if (m_gdb_comm.SendEnvironmentPacket(env_entry, m_packet_timeout) != 0)
+ break;
+ }
+ }
+
+ const uint32_t arg_timeout_seconds = 10;
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket (argv, arg_timeout_seconds);
+ if (arg_packet_err == 0)
+ {
+ std::string error_str;
+ if (m_gdb_comm.GetLaunchSuccess (m_packet_timeout, error_str))
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID (m_packet_timeout));
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i.\n", arg_packet_err);
+ }
+
+ SetID (m_gdb_comm.GetCurrentProcessID (m_packet_timeout));
+ }
+ }
+
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ KillDebugserverProcess ();
+ return error;
+ }
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, response, m_packet_timeout, false))
+ SetPrivateState (SetThreadStopInfo (response));
+
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ error.SetErrorStringWithFormat("Failed to get object file from '%s' for arch %s.\n", module->GetFileSpec().GetFilename().AsCString(), module->GetArchitecture().AsCString());
+ }
+
+ // Return the process ID we have
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::ConnectToDebugserver (const char *host_port)
+{
+ Error error;
+ // Sleep and wait a bit for debugserver to start to listen...
+ std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ std::string connect_url("connect://");
+ connect_url.append (host_port);
+ const uint32_t max_retry_count = 50;
+ uint32_t retry_count = 0;
+ while (!m_gdb_comm.IsConnected())
+ {
+ if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+ {
+ m_gdb_comm.SetConnection (conn_ap.release());
+ break;
+ }
+ retry_count++;
+
+ if (retry_count >= max_retry_count)
+ break;
+
+ usleep (100000);
+ }
+ }
+
+ if (!m_gdb_comm.IsConnected())
+ {
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+
+ m_gdb_comm.SetAckMode (true);
+ if (m_gdb_comm.StartReadThread(&error))
+ {
+ // Send an initial ack
+ m_gdb_comm.SendAck('+');
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ m_debugserver_monitor = Host::StartMonitoringChildProcess (MonitorDebugserverProcess,
+ (void*)(intptr_t)GetID(), // Pass the inferior pid in the thread argument (which is a void *)
+ m_debugserver_pid,
+ false);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("QStartNoAckMode", response, 1, false))
+ {
+ if (response.IsOKPacket())
+ m_gdb_comm.SetAckMode (false);
+ }
+
+ BuildDynamicRegisterInfo ();
+ }
+ return error;
+}
+
+void
+ProcessGDBRemote::DidLaunchOrAttach ()
+{
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::DidLaunch()");
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ m_dynamic_loader_ap.reset();
+ }
+ else
+ {
+ m_dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+
+ Module * exe_module = GetTarget().GetExecutableModule ().get();
+ assert(exe_module);
+
+ m_arch_spec = exe_module->GetArchitecture();
+
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ assert(exe_objfile);
+
+ m_byte_order = exe_objfile->GetByteOrder();
+ assert (m_byte_order != eByteOrderInvalid);
+
+ StreamString strm;
+
+ ArchSpec inferior_arch;
+ // See if the GDB server supports the qHostInfo information
+ const char *vendor = m_gdb_comm.GetVendorString().AsCString();
+ const char *os_type = m_gdb_comm.GetOSString().AsCString();
+
+ if (m_arch_spec.IsValid() && m_arch_spec == ArchSpec ("arm"))
+ {
+ // For ARM we can't trust the arch of the process as it could
+ // have an armv6 object file, but be running on armv7 kernel.
+ inferior_arch = m_gdb_comm.GetHostArchitecture();
+ }
+
+ if (!inferior_arch.IsValid())
+ inferior_arch = m_arch_spec;
+
+ if (vendor == NULL)
+ vendor = Host::GetVendorString().AsCString("apple");
+
+ if (os_type == NULL)
+ os_type = Host::GetOSString().AsCString("darwin");
+
+ strm.Printf ("%s-%s-%s", inferior_arch.AsCString(), vendor, os_type);
+
+ std::transform (strm.GetString().begin(),
+ strm.GetString().end(),
+ strm.GetString().begin(),
+ ::tolower);
+
+ m_target_triple.SetCString(strm.GetString().c_str());
+ }
+}
+
+void
+ProcessGDBRemote::DidLaunch ()
+{
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidLaunch();
+}
+
+Error
+ProcessGDBRemote::DoAttach (pid_t attach_pid)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+ // HACK: require arch be set correctly at the target level until we can
+ // figure out a good way to determine the arch of what we are attaching to
+ m_arch_spec = m_target.GetArchitecture();
+
+ //Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ SetPrivateState (eStateAttaching);
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ error = StartDebugserverProcess (host_port,
+ NULL,
+ NULL,
+ NULL,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ m_arch_spec);
+
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ else
+ {
+ error = ConnectToDebugserver (host_port);
+ if (error.Success())
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%x", attach_pid);
+ StringExtractorGDBRemote response;
+ StateType stop_state = m_gdb_comm.SendContinuePacketAndWaitForResponse (this,
+ packet,
+ packet_len,
+ response);
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ SetID (attach_pid);
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ response.SetFilePos(1);
+ SetExitStatus(response.GetHexU8(), NULL);
+ break;
+
+ default:
+ SetExitStatus(-1, "unable to attach to process");
+ break;
+ }
+
+ }
+ }
+ }
+
+ lldb::pid_t pid = GetID();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ KillDebugserverProcess();
+ }
+ return error;
+}
+
+size_t
+ProcessGDBRemote::AttachInputReaderCallback
+(
+ void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ if (notification == eInputReaderGotToken)
+ {
+ ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)baton;
+ if (gdb_process->m_waiting_for_attach)
+ gdb_process->m_waiting_for_attach = false;
+ reader->SetIsDone(true);
+ return 1;
+ }
+ return 0;
+}
+
+Error
+ProcessGDBRemote::DoAttach (const char *process_name, bool wait_for_launch)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+ // HACK: require arch be set correctly at the target level until we can
+ // figure out a good way to determine the arch of what we are attaching to
+ m_arch_spec = m_target.GetArchitecture();
+
+ //Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (process_name && process_name[0])
+ {
+
+ SetPrivateState (eStateAttaching);
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ error = StartDebugserverProcess (host_port,
+ NULL,
+ NULL,
+ NULL,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ m_arch_spec);
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ else
+ {
+ error = ConnectToDebugserver (host_port);
+ if (error.Success())
+ {
+ StreamString packet;
+
+ packet.PutCString("vAttach");
+ if (wait_for_launch)
+ packet.PutCString("Wait");
+ packet.PutChar(';');
+ packet.PutBytesAsRawHex8(process_name, strlen(process_name), eByteOrderHost, eByteOrderHost);
+ StringExtractorGDBRemote response;
+ StateType stop_state = m_gdb_comm.SendContinuePacketAndWaitForResponse (this,
+ packet.GetData(),
+ packet.GetSize(),
+ response);
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ SetID (m_gdb_comm.GetCurrentProcessID(m_packet_timeout));
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ response.SetFilePos(1);
+ SetExitStatus(response.GetHexU8(), NULL);
+ break;
+
+ default:
+ SetExitStatus(-1, "unable to attach to process");
+ break;
+ }
+ }
+ }
+ }
+
+ lldb::pid_t pid = GetID();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ KillDebugserverProcess();
+ }
+ return error;
+}
+
+//
+// if (wait_for_launch)
+// {
+// InputReaderSP reader_sp (new InputReader());
+// StreamString instructions;
+// instructions.Printf("Hit any key to cancel waiting for '%s' to launch...", process_name);
+// error = reader_sp->Initialize (AttachInputReaderCallback, // callback
+// this, // baton
+// eInputReaderGranularityByte,
+// NULL, // End token
+// false);
+//
+// StringExtractorGDBRemote response;
+// m_waiting_for_attach = true;
+// FILE *reader_out_fh = reader_sp->GetOutputFileHandle();
+// while (m_waiting_for_attach)
+// {
+// // Wait for one second for the stop reply packet
+// if (m_gdb_comm.WaitForPacket(response, 1))
+// {
+// // Got some sort of packet, see if it is the stop reply packet?
+// char ch = response.GetChar(0);
+// if (ch == 'T')
+// {
+// m_waiting_for_attach = false;
+// }
+// }
+// else
+// {
+// // Put a period character every second
+// fputc('.', reader_out_fh);
+// }
+// }
+// }
+// }
+// return GetID();
+//}
+
+void
+ProcessGDBRemote::DidAttach ()
+{
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidAttach();
+}
+
+Error
+ProcessGDBRemote::WillResume ()
+{
+ m_continue_packet.Clear();
+ // Start the continue packet we will use to run the target. Each thread
+ // will append what it is supposed to be doing to this packet when the
+ // ThreadList::WillResume() is called. If a thread it supposed
+ // to stay stopped, then don't append anything to this string.
+ m_continue_packet.Printf("vCont");
+ return Error();
+}
+
+Error
+ProcessGDBRemote::DoResume ()
+{
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::Resume()");
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (m_continue_packet.GetData(), m_continue_packet.GetSize()));
+ return Error();
+}
+
+size_t
+ProcessGDBRemote::GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site)
+{
+ const uint8_t *trap_opcode = NULL;
+ uint32_t trap_opcode_size = 0;
+
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ //static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+ static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+
+ switch (m_arch_spec.GetCPUType())
+ {
+ case CPU_TYPE_ARM:
+ // TODO: fill this in for ARM. We need to dig up the symbol for
+ // the address in the breakpoint locaiton and figure out if it is
+ // an ARM or Thumb breakpoint.
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ trap_opcode = g_ppc_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ break;
+
+ default:
+ assert(!"Unhandled architecture in ProcessGDBRemote::GetSoftwareBreakpointTrapOpcode()");
+ return 0;
+ }
+
+ if (trap_opcode && trap_opcode_size)
+ {
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ }
+ return 0;
+}
+
+uint32_t
+ProcessGDBRemote::UpdateThreadListIfNeeded ()
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD);
+ if (log && log->GetMask().IsSet(GDBR_LOG_VERBOSE))
+ log->Printf ("ProcessGDBRemote::%s (pid = %i)", __FUNCTION__, GetID());
+
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID())
+ {
+ // Update the thread list's stop id immediately so we don't recurse into this function.
+ ThreadList curr_thread_list (this);
+ curr_thread_list.SetStopID(stop_id);
+
+ Error err;
+ StringExtractorGDBRemote response;
+ for (m_gdb_comm.SendPacketAndWaitForResponse("qfThreadInfo", response, 1, false);
+ response.IsNormalPacket();
+ m_gdb_comm.SendPacketAndWaitForResponse("qsThreadInfo", response, 1, false))
+ {
+ char ch = response.GetChar();
+ if (ch == 'l')
+ break;
+ if (ch == 'm')
+ {
+ do
+ {
+ tid_t tid = response.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID);
+
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ ThreadSP thread_sp (GetThreadList().FindThreadByID (tid, false));
+ if (thread_sp)
+ thread_sp->GetRegisterContext()->Invalidate();
+ else
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ curr_thread_list.AddThread(thread_sp);
+ }
+
+ ch = response.GetChar();
+ } while (ch == ',');
+ }
+ }
+
+ m_thread_list = curr_thread_list;
+
+ SetThreadStopInfo (m_last_stop_packet);
+ }
+ return GetThreadList().GetSize(false);
+}
+
+
+StateType
+ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
+{
+ const char stop_type = stop_packet.GetChar();
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ // Stop with signal and thread info
+ const uint8_t signo = stop_packet.GetHexU8();
+ std::string name;
+ std::string value;
+ std::string thread_name;
+ uint32_t exc_type = 0;
+ std::vector<uint64_t> exc_data;
+ uint32_t tid = LLDB_INVALID_THREAD_ID;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ uint32_t exc_data_count = 0;
+ while (stop_packet.GetNameColonValue(name, value))
+ {
+ if (name.compare("metype") == 0)
+ {
+ // exception type in big endian hex
+ exc_type = Args::StringToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("mecount") == 0)
+ {
+ // exception count in big endian hex
+ exc_data_count = Args::StringToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("medata") == 0)
+ {
+ // exception data in big endian hex
+ exc_data.push_back(Args::StringToUInt64 (value.c_str(), 0, 16));
+ }
+ else if (name.compare("thread") == 0)
+ {
+ // thread in big endian hex
+ tid = Args::StringToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("name") == 0)
+ {
+ thread_name.swap (value);
+ }
+ else if (name.compare("dispatchqaddr") == 0)
+ {
+ thread_dispatch_qaddr = Args::StringToUInt64 (value.c_str(), 0, 16);
+ }
+ }
+ ThreadSP thread_sp (m_thread_list.FindThreadByID(tid, false));
+
+ if (thread_sp)
+ {
+ ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
+
+ gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
+ gdb_thread->SetName (thread_name.empty() ? thread_name.c_str() : NULL);
+ Thread::StopInfo& stop_info = gdb_thread->GetStopInfoRef();
+ gdb_thread->SetStopInfoStopID (GetStopID());
+ if (exc_type != 0)
+ {
+ if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && exc_data[0] == EXC_SOFT_SIGNAL)
+ {
+ stop_info.SetStopReasonWithSignal(exc_data[1]);
+ }
+#if defined (MACH_EXC_DATA0_SOFTWARE_BREAKPOINT)
+ else if (exc_type == EXC_BREAKPOINT && exc_data[0] == MACH_EXC_DATA0_SOFTWARE_BREAKPOINT)
+ {
+ addr_t pc = gdb_thread->GetRegisterContext()->GetPC();
+ user_id_t break_id = GetBreakpointSiteList().FindIDByAddress(pc);
+ if (break_id == LLDB_INVALID_BREAK_ID)
+ {
+ //log->Printf("got EXC_BREAKPOINT at 0x%llx but didn't find a breakpoint site.\n", pc);
+ stop_info.SetStopReasonWithException(exc_type, exc_data.size());
+ for (uint32_t i=0; i<exc_data.size(); ++i)
+ stop_info.SetExceptionDataAtIndex(i, exc_data[i]);
+ }
+ else
+ {
+ stop_info.Clear ();
+ stop_info.SetStopReasonWithBreakpointSiteID (break_id);
+ }
+ }
+#endif
+#if defined (MACH_EXC_DATA0_TRACE)
+ else if (exc_type == EXC_BREAKPOINT && exc_data[0] == MACH_EXC_DATA0_TRACE)
+ {
+ stop_info.SetStopReasonToTrace ();
+ }
+#endif
+ else
+ {
+ stop_info.SetStopReasonWithException(exc_type, exc_data.size());
+ for (uint32_t i=0; i<exc_data.size(); ++i)
+ stop_info.SetExceptionDataAtIndex(i, exc_data[i]);
+ }
+ }
+ else if (signo)
+ {
+ stop_info.SetStopReasonWithSignal(signo);
+ }
+ else
+ {
+ stop_info.SetStopReasonToNone();
+ }
+ }
+ return eStateStopped;
+ }
+ break;
+
+ case 'W':
+ // process exited
+ return eStateExited;
+
+ default:
+ break;
+ }
+ return eStateInvalid;
+}
+
+void
+ProcessGDBRemote::RefreshStateAfterStop ()
+{
+ // We must be attaching if we don't already have a valid architecture
+ if (!m_arch_spec.IsValid())
+ {
+ Module *exe_module = GetTarget().GetExecutableModule().get();
+ if (exe_module)
+ m_arch_spec = exe_module->GetArchitecture();
+ }
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+
+ // Discover new threads:
+ UpdateThreadListIfNeeded ();
+}
+
+Error
+ProcessGDBRemote::DoHalt ()
+{
+ Error error;
+ if (m_gdb_comm.IsRunning())
+ {
+ bool timed_out = false;
+ if (!m_gdb_comm.SendInterrupt (2, &timed_out))
+ {
+ if (timed_out)
+ error.SetErrorString("timed out sending interrupt packet");
+ else
+ error.SetErrorString("unknown error sending interrupt packet");
+ }
+ }
+ return error;
+}
+
+Error
+ProcessGDBRemote::WillDetach ()
+{
+ Error error;
+ const StateType state = m_private_state.GetValue();
+
+ if (IsRunning(state))
+ error.SetErrorString("Process must be stopped in order to detach.");
+
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::DoDestroy ()
+{
+ Error error;
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy()");
+
+ // Interrupt if our inferior is running...
+ m_gdb_comm.SendInterrupt (1);
+ DisableAllBreakpointSites ();
+ SetExitStatus(-1, "process killed");
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("k", response, 2, false))
+ {
+ if (log)
+ {
+ if (response.IsOKPacket())
+ log->Printf ("ProcessGDBRemote::DoDestroy() kill was successful");
+ else
+ log->Printf ("ProcessGDBRemote::DoDestroy() kill failed: %s", response.GetStringRef().c_str());
+ }
+ }
+
+ StopAsyncThread ();
+ m_gdb_comm.StopReadThread();
+ KillDebugserverProcess ();
+ return error;
+}
+
+ByteOrder
+ProcessGDBRemote::GetByteOrder () const
+{
+ return m_byte_order;
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessGDBRemote::IsAlive ()
+{
+ return m_gdb_comm.IsConnected();
+}
+
+addr_t
+ProcessGDBRemote::GetImageInfoAddress()
+{
+ if (!m_gdb_comm.IsRunning())
+ {
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, 2, false))
+ {
+ if (response.IsNormalPacket())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+DynamicLoader *
+ProcessGDBRemote::GetDynamicLoader()
+{
+ return m_dynamic_loader_ap.get();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ if (size > m_max_memory_size)
+ {
+ // Keep memory read sizes down to a sane limit. This function will be
+ // called multiple times in order to complete the task by
+ // lldb_private::Process so it is ok to do this.
+ size = m_max_memory_size;
+ }
+
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "m%llx,%zx", (uint64_t)addr, size);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, true))
+ {
+ if (response.IsNormalPacket())
+ {
+ error.Clear();
+ return response.GetHexBytes(buf, size, '\xdd');
+ }
+ else if (response.IsErrorPacket())
+ error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str());
+ else if (response.IsUnsupportedPacket())
+ error.SetErrorStringWithFormat("'%s' packet unsupported", packet);
+ else
+ error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet, response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to sent packet: '%s'", packet);
+ }
+ return 0;
+}
+
+size_t
+ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ StreamString packet;
+ packet.Printf("M%llx,%zx:", addr, size);
+ packet.PutBytesAsRawHex8(buf, size, eByteOrderHost, eByteOrderHost);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, 2, true))
+ {
+ if (response.IsOKPacket())
+ {
+ error.Clear();
+ return size;
+ }
+ else if (response.IsErrorPacket())
+ error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str());
+ else if (response.IsUnsupportedPacket())
+ error.SetErrorStringWithFormat("'%s' packet unsupported", packet.GetString().c_str());
+ else
+ error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to sent packet: '%s'", packet.GetString().c_str());
+ }
+ return 0;
+}
+
+lldb::addr_t
+ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
+{
+ addr_t allocated_addr = m_gdb_comm.AllocateMemory (size, permissions, m_packet_timeout);
+ if (allocated_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %u", size, permissions);
+ else
+ error.Clear();
+ return allocated_addr;
+}
+
+Error
+ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
+{
+ Error error;
+ if (!m_gdb_comm.DeallocateMemory (addr, m_packet_timeout))
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%llx", addr);
+ return error;
+}
+
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+
+size_t
+ProcessGDBRemote::GetSTDOUT (char *buf, size_t buf_size, Error &error)
+{
+ Mutex::Locker locker(m_stdio_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.data(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.data(), bytes_available);
+ m_stdout_data.clear();
+
+ //ResetEventBits(eBroadcastBitSTDOUT);
+ }
+ }
+ return bytes_available;
+}
+
+size_t
+ProcessGDBRemote::GetSTDERR (char *buf, size_t buf_size, Error &error)
+{
+ // Can we get STDERR through the remote protocol?
+ return 0;
+}
+
+size_t
+ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error)
+{
+ if (m_stdio_communication.IsConnected())
+ {
+ ConnectionStatus status;
+ m_stdio_communication.Write(src, src_len, status, NULL);
+ }
+ return 0;
+}
+
+Error
+ProcessGDBRemote::EnableBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS);
+ user_id_t site_id = bp_site->GetID();
+ const addr_t addr = bp_site->GetLoadAddress();
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableBreakpoint (size_id = %d) address = 0x%llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableBreakpoint (size_id = %d) address = 0x%llx -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+ else
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ if (bp_site->HardwarePreferred())
+ {
+ // Try and set hardware breakpoint, and if that fails, fall through
+ // and set a software breakpoint?
+ }
+
+ if (m_z0_supported)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "Z0,%llx,%zx", addr, bp_op_size);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, true))
+ {
+ if (response.IsUnsupportedPacket())
+ {
+ // Disable z packet support and try again
+ m_z0_supported = 0;
+ return EnableBreakpoint (bp_site);
+ }
+ else if (response.IsOKPacket())
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eExternal);
+ return error;
+ }
+ else
+ {
+ uint8_t error_byte = response.GetError();
+ if (error_byte)
+ error.SetErrorStringWithFormat("%x packet failed with error: %i (0x%2.2x).\n", packet, error_byte, error_byte);
+ }
+ }
+ }
+ else
+ {
+ return EnableSoftwareBreakpoint (bp_site);
+ }
+ }
+
+ if (log)
+ {
+ const char *err_string = error.AsCString();
+ log->Printf ("ProcessGDBRemote::EnableBreakpoint() error for breakpoint at 0x%8.8llx: %s",
+ bp_site->GetLoadAddress(),
+ err_string ? err_string : "NULL");
+ }
+ // We shouldn't reach here on a successful breakpoint enable...
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ addr_t addr = bp_site->GetLoadAddress();
+ user_id_t site_id = bp_site->GetID();
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ if (bp_site->IsHardware())
+ {
+ // TODO: disable hardware breakpoint...
+ }
+ else
+ {
+ if (m_z0_supported)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "z0,%llx,%zx", addr, bp_op_size);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, true))
+ {
+ if (response.IsUnsupportedPacket())
+ {
+ error.SetErrorString("Breakpoint site was set with Z packet, yet remote debugserver states z packets are not supported.");
+ }
+ else if (response.IsOKPacket())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS", site_id, (uint64_t)addr);
+ bp_site->SetEnabled(false);
+ return error;
+ }
+ else
+ {
+ uint8_t error_byte = response.GetError();
+ if (error_byte)
+ error.SetErrorStringWithFormat("%x packet failed with error: %i (0x%2.2x).\n", packet, error_byte, error_byte);
+ }
+ }
+ }
+ else
+ {
+ return DisableSoftwareBreakpoint (bp_site);
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS (already disabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::EnableWatchpoint (WatchpointLocation *wp)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableWatchpoint(watchID = %d)", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
+ return error;
+ }
+ else
+ {
+ // Pass down an appropriate z/Z packet...
+ error.SetErrorString("watchpoints not supported");
+ }
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint location argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableWatchpoint (WatchpointLocation *wp)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS);
+
+ addr_t addr = wp->GetLoadAddress();
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %d) addr = 0x%8.8llx", watchID, (uint64_t)addr);
+
+ if (wp->IsHardware())
+ {
+ // Pass down an appropriate z/Z packet...
+ error.SetErrorString("watchpoints not supported");
+ }
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint location argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+void
+ProcessGDBRemote::Clear()
+{
+ m_flags = 0;
+ m_thread_list.Clear();
+ {
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.clear();
+ }
+ DestoryLibUnwindAddressSpace();
+}
+
+Error
+ProcessGDBRemote::DoSignal (int signo)
+{
+ Error error;
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoSignal (signal = %d)", signo);
+
+ if (!m_gdb_comm.SendAsyncSignal (signo))
+ error.SetErrorStringWithFormat("failed to send signal %i", signo);
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::DoDetach()
+{
+ Error error;
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDetach()");
+
+ // if (DoSIGSTOP (true))
+ // {
+ // CloseChildFileDescriptors ();
+ //
+ // // Scope for "locker" so we can reply to all of our exceptions (the SIGSTOP
+ // // exception).
+ // {
+ // Mutex::Locker locker(m_exception_messages_mutex);
+ // ReplyToAllExceptions();
+ // }
+ //
+ // // Shut down the exception thread and cleanup our exception remappings
+ // Task().ShutDownExceptionThread();
+ //
+ // pid_t pid = GetID();
+ //
+ // // Detach from our process while we are stopped.
+ // errno = 0;
+ //
+ // // Detach from our process
+ // ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
+ //
+ // error.SetErrorToErrno();
+ //
+ // if (log || error.Fail())
+ // error.PutToLog(log, "::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
+ //
+ // // Resume our task
+ // Task().Resume();
+ //
+ // // NULL our task out as we have already retored all exception ports
+ // Task().Clear();
+ //
+ // // Clear out any notion of the process we once were
+ // Clear();
+ //
+ // SetPrivateState (eStateDetached);
+ // return true;
+ // }
+ return error;
+}
+
+void
+ProcessGDBRemote::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ ProcessGDBRemote *process = (ProcessGDBRemote *)baton;
+ process->AppendSTDOUT(static_cast<const char *>(src), src_len);
+}
+
+void
+ProcessGDBRemote::AppendSTDOUT (const char* s, size_t len)
+{
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::%s (<%d> %s) ...", __FUNCTION__, len, s);
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.append(s, len);
+
+ // FIXME: Make a real data object for this and put it out.
+ BroadcastEventIfUnique (eBroadcastBitSTDOUT);
+}
+
+
+Error
+ProcessGDBRemote::StartDebugserverProcess
+(
+ const char *debugserver_url, // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
+ char const *inferior_argv[], // Arguments for the inferior program including the path to the inferior itself as the first argument
+ char const *inferior_envp[], // Environment to pass along to the inferior program
+ char const *stdio_path,
+ lldb::pid_t attach_pid, // If inferior inferior_argv == NULL, and attach_pid != LLDB_INVALID_PROCESS_ID then attach to this attach_pid
+ const char *attach_name, // Wait for the next process to launch whose basename matches "attach_name"
+ bool wait_for_launch, // Wait for the process named "attach_name" to launch
+ ArchSpec& inferior_arch // The arch of the inferior that we will launch
+)
+{
+ Error error;
+ if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ FileSpec debugserver_file_spec;
+ char debugserver_path[PATH_MAX];
+
+ // Always check to see if we have an environment override for the path
+ // to the debugserver to use and use it if we do.
+ const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
+ if (env_debugserver_path)
+ debugserver_file_spec.SetFile (env_debugserver_path);
+ else
+ debugserver_file_spec = g_debugserver_file_spec;
+ bool debugserver_exists = debugserver_file_spec.Exists();
+ if (!debugserver_exists)
+ {
+ // The debugserver binary is in the LLDB.framework/Resources
+ // directory.
+ FileSpec framework_file_spec (Host::GetModuleFileSpecForHostAddress ((void *)lldb_private::Initialize));
+ const char *framework_dir = framework_file_spec.GetDirectory().AsCString();
+ const char *lldb_framework = ::strstr (framework_dir, "/LLDB.framework");
+
+ if (lldb_framework)
+ {
+ int len = lldb_framework - framework_dir + strlen ("/LLDB.framework");
+ ::snprintf (debugserver_path,
+ sizeof(debugserver_path),
+ "%.*s/Resources/%s",
+ len,
+ framework_dir,
+ DEBUGSERVER_BASENAME);
+ debugserver_file_spec.SetFile (debugserver_path);
+ debugserver_exists = debugserver_file_spec.Exists();
+ }
+
+ if (debugserver_exists)
+ {
+ g_debugserver_file_spec = debugserver_file_spec;
+ }
+ else
+ {
+ g_debugserver_file_spec.Clear();
+ debugserver_file_spec.Clear();
+ }
+ }
+
+ if (debugserver_exists)
+ {
+ debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
+
+ m_stdio_communication.Clear();
+ posix_spawnattr_t attr;
+
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+
+ Error local_err; // Errors that don't affect the spawning.
+ if (log)
+ log->Printf ("%s ( path='%s', argv=%p, envp=%p, arch=%s )", __FUNCTION__, debugserver_path, inferior_argv, inferior_envp, inferior_arch.AsCString());
+ error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
+ if (error.Fail())
+ return error;;
+
+#if !defined (__arm__)
+
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ cpu_type_t cpu = inferior_arch.GetCPUType();
+ if (cpu != 0 && cpu != CPU_TYPE_ANY && cpu != LLDB_INVALID_CPUTYPE)
+ {
+ size_t ocount = 0;
+ error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu, ocount);
+
+ if (error.Fail() != 0 || ocount != 1)
+ return error;
+ }
+
+#endif
+
+ Args debugserver_args;
+ char arg_cstr[PATH_MAX];
+ bool launch_process = true;
+
+ if (inferior_argv == NULL && attach_pid != LLDB_INVALID_PROCESS_ID)
+ launch_process = false;
+ else if (attach_name)
+ launch_process = false; // Wait for a process whose basename matches that in inferior_argv[0]
+
+ bool pass_stdio_path_to_debugserver = true;
+ lldb_utility::PseudoTerminal pty;
+ if (stdio_path == NULL)
+ {
+ pass_stdio_path_to_debugserver = false;
+ if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
+ {
+ struct termios stdin_termios;
+ if (::tcgetattr (pty.GetMasterFileDescriptor(), &stdin_termios) == 0)
+ {
+ stdin_termios.c_lflag &= ~ECHO; // Turn off echoing
+ stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
+ ::tcsetattr (pty.GetMasterFileDescriptor(), TCSANOW, &stdin_termios);
+ }
+ stdio_path = pty.GetSlaveName (NULL, 0);
+ }
+ }
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(debugserver_path);
+ debugserver_args.AppendArgument(debugserver_url);
+ debugserver_args.AppendArgument("--native-regs"); // use native registers, not the GDB registers
+ debugserver_args.AppendArgument("--setsid"); // make debugserver run in its own session so
+ // signals generated by special terminal key
+ // sequences (^C) don't affect debugserver
+
+ // Only set the inferior
+ if (launch_process)
+ {
+ if (stdio_path && pass_stdio_path_to_debugserver)
+ {
+ debugserver_args.AppendArgument("-s"); // short for --stdio-path
+ StreamString strm;
+ strm.Printf("'%s'", stdio_path);
+ debugserver_args.AppendArgument(strm.GetData()); // path to file to have inferior open as it's STDIO
+ }
+ }
+
+ const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
+ if (env_debugserver_log_file)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+
+ const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
+ if (env_debugserver_log_flags)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
+// debugserver_args.AppendArgument("--log-flags=0x800e0e");
+
+ // Now append the program arguments
+ if (launch_process)
+ {
+ if (inferior_argv)
+ {
+ // Terminate the debugserver args so we can now append the inferior args
+ debugserver_args.AppendArgument("--");
+
+ for (int i = 0; inferior_argv[i] != NULL; ++i)
+ debugserver_args.AppendArgument (inferior_argv[i]);
+ }
+ else
+ {
+ // Will send environment entries with the 'QEnvironment:' packet
+ // Will send arguments with the 'A' packet
+ }
+ }
+ else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
+ debugserver_args.AppendArgument (arg_cstr);
+ }
+ else if (attach_name && attach_name[0])
+ {
+ if (wait_for_launch)
+ debugserver_args.AppendArgument ("--waitfor");
+ else
+ debugserver_args.AppendArgument ("--attach");
+ debugserver_args.AppendArgument (attach_name);
+ }
+
+ Error file_actions_err;
+ posix_spawn_file_actions_t file_actions;
+#if DONT_CLOSE_DEBUGSERVER_STDIO
+ file_actions_err.SetErrorString ("Remove this after uncommenting the code block below.");
+#else
+ file_actions_err.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+ if (file_actions_err.Success())
+ {
+ ::posix_spawn_file_actions_addclose (&file_actions, STDIN_FILENO);
+ ::posix_spawn_file_actions_addclose (&file_actions, STDOUT_FILENO);
+ ::posix_spawn_file_actions_addclose (&file_actions, STDERR_FILENO);
+ }
+#endif
+
+ if (log)
+ {
+ StreamString strm;
+ debugserver_args.Dump (&strm);
+ log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData());
+ }
+
+ error.SetError(::posix_spawnp (&m_debugserver_pid,
+ debugserver_path,
+ file_actions_err.Success() ? &file_actions : NULL,
+ &attr,
+ debugserver_args.GetArgumentVector(),
+ (char * const*)inferior_envp),
+ eErrorTypePOSIX);
+
+ if (file_actions_err.Success())
+ ::posix_spawn_file_actions_destroy (&file_actions);
+
+ // We have seen some cases where posix_spawnp was returning a valid
+ // looking pid even when an error was returned, so clear it out
+ if (error.Fail())
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", m_debugserver_pid, debugserver_path, NULL, &attr, inferior_argv, inferior_envp);
+
+// if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+// {
+// std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor (pty.ReleaseMasterFileDescriptor(), true));
+// if (conn_ap.get())
+// {
+// m_stdio_communication.SetConnection(conn_ap.release());
+// if (m_stdio_communication.IsConnected())
+// {
+// m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
+// m_stdio_communication.StartReadThread();
+// }
+// }
+// }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unable to locate " DEBUGSERVER_BASENAME ".\n");
+ }
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ StartAsyncThread ();
+ }
+ return error;
+}
+
+bool
+ProcessGDBRemote::MonitorDebugserverProcess
+(
+ void *callback_baton,
+ lldb::pid_t debugserver_pid,
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ // We pass in the ProcessGDBRemote inferior process it and name it
+ // "gdb_remote_pid". The process ID is passed in the "callback_baton"
+ // pointer value itself, thus we need the double cast...
+
+ // "debugserver_pid" argument passed in is the process ID for
+ // debugserver that we are tracking...
+
+ lldb::pid_t gdb_remote_pid = (lldb::pid_t)(intptr_t)callback_baton;
+ TargetSP target_sp(Debugger::GetSharedInstance().GetTargetList().FindTargetWithProcessID (gdb_remote_pid));
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ // Sleep for a half a second to make sure our inferior process has
+ // time to set its exit status before we set it incorrectly when
+ // both the debugserver and the inferior process shut down.
+ usleep (500000);
+ // If our process hasn't yet exited, debugserver might have died.
+ // If the process did exit, the we are reaping it.
+ if (process_sp->GetState() != eStateExited)
+ {
+ char error_str[1024];
+ if (signo)
+ {
+ const char *signal_cstr = process_sp->GetUnixSignals().GetSignalAsCString (signo);
+ if (signal_cstr)
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr);
+ else
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %i", signo);
+ }
+ else
+ {
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", exit_status);
+ }
+
+ process_sp->SetExitStatus (-1, error_str);
+ }
+ else
+ {
+ ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)process_sp.get();
+ // Debugserver has exited we need to let our ProcessGDBRemote
+ // know that it no longer has a debugserver instance
+ gdb_process->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ // We are returning true to this function below, so we can
+ // forget about the monitor handle.
+ gdb_process->m_debugserver_monitor = 0;
+ }
+ }
+ }
+ return true;
+}
+
+void
+ProcessGDBRemote::KillDebugserverProcess ()
+{
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::kill (m_debugserver_pid, SIGINT);
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+}
+
+void
+ProcessGDBRemote::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+
+ Log::Callbacks log_callbacks = {
+ ProcessGDBRemoteLog::DisableLog,
+ ProcessGDBRemoteLog::EnableLog,
+ ProcessGDBRemoteLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessGDBRemote::GetPluginNameStatic(), log_callbacks);
+ }
+}
+
+bool
+ProcessGDBRemote::SetCurrentGDBRemoteThread (int tid)
+{
+ if (m_curr_tid == tid)
+ return true;
+
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, false))
+ {
+ if (response.IsOKPacket())
+ {
+ m_curr_tid = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ProcessGDBRemote::SetCurrentGDBRemoteThreadForRun (int tid)
+{
+ if (m_curr_tid_run == tid)
+ return true;
+
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, false))
+ {
+ if (response.IsOKPacket())
+ {
+ m_curr_tid_run = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+ProcessGDBRemote::ResetGDBRemoteState ()
+{
+ // Reset and GDB remote state
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+ m_curr_tid_run = LLDB_INVALID_THREAD_ID;
+ m_z0_supported = 1;
+}
+
+
+bool
+ProcessGDBRemote::StartAsyncThread ()
+{
+ ResetGDBRemoteState ();
+
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+ m_async_thread = Host::ThreadCreate ("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL);
+ return m_async_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+void
+ProcessGDBRemote::StopAsyncThread ()
+{
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
+
+ // Stop the stdio thread
+ if (m_async_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ Host::ThreadJoin (m_async_thread, NULL, NULL);
+ }
+}
+
+
+void *
+ProcessGDBRemote::AsyncThread (void *arg)
+{
+ ProcessGDBRemote *process = (ProcessGDBRemote*) arg;
+
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
+
+ Listener listener ("ProcessGDBRemote::AsyncThread");
+ EventSP event_sp;
+ const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
+ eBroadcastBitAsyncThreadShouldExit;
+
+ if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask)
+ {
+ bool done = false;
+ while (!done)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID());
+ if (listener.WaitForEvent (NULL, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ switch (event_type)
+ {
+ case eBroadcastBitAsyncContinue:
+ {
+ const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get());
+
+ if (continue_packet)
+ {
+ const char *continue_cstr = (const char *)continue_packet->GetBytes ();
+ const size_t continue_cstr_len = continue_packet->GetByteSize ();
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr);
+
+ process->SetPrivateState(eStateRunning);
+ StringExtractorGDBRemote response;
+ StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response);
+
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ process->m_last_stop_packet = response;
+ process->m_last_stop_packet.SetFilePos (0);
+ process->SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ process->m_last_stop_packet = response;
+ process->m_last_stop_packet.SetFilePos (0);
+ response.SetFilePos(1);
+ process->SetExitStatus(response.GetHexU8(), NULL);
+ done = true;
+ break;
+
+ case eStateInvalid:
+ break;
+
+ default:
+ process->SetPrivateState (stop_state);
+ break;
+ }
+ }
+ }
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID());
+ done = true;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type);
+ done = true;
+ break;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID());
+ done = true;
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
+
+ process->m_async_thread = LLDB_INVALID_HOST_THREAD;
+ return NULL;
+}
+
+lldb_private::unw_addr_space_t
+ProcessGDBRemote::GetLibUnwindAddressSpace ()
+{
+ unw_targettype_t target_type = UNW_TARGET_UNSPECIFIED;
+ if (m_target.GetArchitecture().GetCPUType() == CPU_TYPE_I386)
+ target_type = UNW_TARGET_I386;
+ if (m_target.GetArchitecture().GetCPUType() == CPU_TYPE_X86_64)
+ target_type = UNW_TARGET_X86_64;
+
+ if (m_libunwind_addr_space)
+ {
+ if (m_libunwind_target_type != target_type)
+ DestoryLibUnwindAddressSpace();
+ else
+ return m_libunwind_addr_space;
+ }
+ unw_accessors_t callbacks = get_macosx_libunwind_callbacks ();
+ m_libunwind_addr_space = unw_create_addr_space (&callbacks, target_type);
+ if (m_libunwind_addr_space)
+ m_libunwind_target_type = target_type;
+ else
+ m_libunwind_target_type = UNW_TARGET_UNSPECIFIED;
+ return m_libunwind_addr_space;
+}
+
+void
+ProcessGDBRemote::DestoryLibUnwindAddressSpace ()
+{
+ if (m_libunwind_addr_space)
+ {
+ unw_destroy_addr_space (m_libunwind_addr_space);
+ m_libunwind_addr_space = NULL;
+ }
+ m_libunwind_target_type = UNW_TARGET_UNSPECIFIED;
+}
+
+
+const char *
+ProcessGDBRemote::GetDispatchQueueNameForThread
+(
+ addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name
+)
+{
+ dispatch_queue_name.clear();
+ if (thread_dispatch_qaddr != 0 && thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ // Cache the dispatch_queue_offsets_addr value so we don't always have
+ // to look it up
+ if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ {
+ ModuleSP module_sp(GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib")));
+ if (module_sp.get() == NULL)
+ return NULL;
+
+ const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData);
+ if (dispatch_queue_offsets_symbol)
+ m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(this);
+
+ if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ return NULL;
+ }
+
+ uint8_t memory_buffer[8];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer), GetByteOrder(), GetAddressByteSize());
+
+ // Excerpt from src/queue_private.h
+ struct dispatch_queue_offsets_s
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ } dispatch_queue_offsets;
+
+
+ Error error;
+ if (ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
+ {
+ uint32_t data_offset = 0;
+ if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
+ {
+ if (ReadMemory (thread_dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t queue_addr = data.GetAddress(&data_offset);
+ lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
+ dispatch_queue_name.resize(dispatch_queue_offsets.dqo_label_size, '\0');
+ size_t bytes_read = ReadMemory (label_addr, &dispatch_queue_name[0], dispatch_queue_offsets.dqo_label_size, error);
+ if (bytes_read < dispatch_queue_offsets.dqo_label_size)
+ dispatch_queue_name.erase (bytes_read);
+ }
+ }
+ }
+ }
+ if (dispatch_queue_name.empty())
+ return NULL;
+ return dispatch_queue_name.c_str();
+}
+
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
new file mode 100644
index 0000000..cd5bab0
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -0,0 +1,404 @@
+//===-- ProcessGDBRemote.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_ProcessGDBRemote_h_
+#define liblldb_ProcessGDBRemote_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "GDBRemoteCommunication.h"
+#include "StringExtractor.h"
+#include "GDBRemoteRegisterContext.h"
+#include "libunwind.h"
+
+class ThreadGDBRemote;
+
+class ProcessGDBRemote : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static Process*
+ CreateInstance (lldb_private::Target& target, lldb_private::Listener &listener);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessGDBRemote(lldb_private::Target& target, lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessGDBRemote();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb_private::Target &target);
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillLaunch (lldb_private::Module* module);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module* module,
+ char const *argv[], // Can be NULL
+ char const *envp[], // Can be NULL
+ const char *stdin_path, // Can be NULL
+ const char *stdout_path, // Can be NULL
+ const char *stderr_path); // Can be NULL
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb_private::Error
+ WillAttach (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ WillAttach (const char *process_name, bool wait_for_launch);
+
+ lldb_private::Error
+ WillLaunchOrAttach ();
+
+ virtual lldb_private::Error
+ DoAttach (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttach (const char *process_name, bool wait_for_launch);
+
+ virtual void
+ DidAttach ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillResume ();
+
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt ();
+
+ virtual lldb_private::Error
+ WillDetach ();
+
+ virtual lldb_private::Error
+ DoDetach ();
+
+ virtual lldb_private::Error
+ DoSignal (int signal);
+
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ virtual lldb::addr_t
+ GetImageInfoAddress();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t
+ GetSTDOUT (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ GetSTDERR (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+protected:
+ friend class ThreadGDBRemote;
+ friend class GDBRemoteCommunication;
+ friend class GDBRemoteRegisterContext;
+
+ bool
+ SetCurrentGDBRemoteThread (int tid);
+
+ bool
+ SetCurrentGDBRemoteThreadForRun (int tid);
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ IsRunning ( lldb::StateType state )
+ {
+ return state == lldb::eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( lldb::StateType state)
+ {
+ return state == lldb::eStateStepping;
+ }
+ bool
+ CanResume ( lldb::StateType state)
+ {
+ return state == lldb::eStateStopped;
+ }
+
+ bool
+ HasExited (lldb::StateType state)
+ {
+ return state == lldb::eStateExited;
+ }
+
+ bool
+ ProcessIDIsValid ( ) const;
+
+ static void
+ STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
+ void
+ AppendSTDOUT (const char* s, size_t len);
+
+ lldb_private::ArchSpec&
+ GetArchSpec()
+ {
+ return m_arch_spec;
+ }
+ const lldb_private::ArchSpec&
+ GetArchSpec() const
+ {
+ return m_arch_spec;
+ }
+
+ void
+ Clear ( );
+
+ lldb_private::Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ uint32_t
+ UpdateThreadListIfNeeded ();
+
+ lldb_private::Error
+ StartDebugserverProcess (const char *debugserver_url, // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
+ char const *inferior_argv[],
+ char const *inferior_envp[],
+ const char *stdin_path,
+ lldb::pid_t attach_pid, // If inferior inferior_argv == NULL, then attach to this pid
+ const char *attach_pid_name, // Wait for the next process to launch whose basename matches "attach_wait_name"
+ bool wait_for_launch, // Wait for the process named "attach_wait_name" to launch
+ lldb_private::ArchSpec& arch_spec);
+
+ void
+ KillDebugserverProcess ();
+
+ void
+ BuildDynamicRegisterInfo ();
+
+ GDBRemoteCommunication &
+ GetGDBRemote()
+ {
+ return m_gdb_comm;
+ }
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ eBroadcastBitAsyncThreadShouldExit = (1 << 1)
+ };
+
+
+ std::auto_ptr<lldb_private::DynamicLoader> m_dynamic_loader_ap;
+ lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
+ lldb_private::Communication m_stdio_communication;
+ lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio
+ std::string m_stdout_data;
+ lldb_private::ArchSpec m_arch_spec;
+ lldb::ByteOrder m_byte_order;
+ GDBRemoteCommunication m_gdb_comm;
+ lldb::pid_t m_debugserver_pid;
+ uint32_t m_debugserver_monitor;
+ StringExtractor m_last_stop_packet;
+ GDBRemoteDynamicRegisterInfo m_register_info;
+ lldb_private::Broadcaster m_async_broadcaster;
+ lldb::thread_t m_async_thread;
+ // Current GDB remote state. Any members added here need to be reset to
+ // proper default values in ResetGDBRemoteState ().
+ lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations
+ lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc
+ uint32_t m_z0_supported:1; // Set to non-zero if Z0 and z0 packets are supported
+ lldb_private::StreamString m_continue_packet;
+ lldb::addr_t m_dispatch_queue_offsets_addr;
+ uint32_t m_packet_timeout;
+ size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory
+ lldb_private::unw_targettype_t m_libunwind_target_type;
+ lldb_private::unw_addr_space_t m_libunwind_addr_space; // libunwind address space object for this process.
+ bool m_waiting_for_attach;
+
+ void
+ ResetGDBRemoteState ();
+
+ bool
+ StartAsyncThread ();
+
+ void
+ StopAsyncThread ();
+
+ static void *
+ AsyncThread (void *arg);
+
+ static bool
+ MonitorDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ int signo, // Zero for no signal
+ int exit_status); // Exit value of process if signal is zero
+
+ lldb::StateType
+ SetThreadStopInfo (StringExtractor& stop_packet);
+
+ void
+ DidLaunchOrAttach ();
+
+ lldb_private::Error
+ ConnectToDebugserver (const char *host_port);
+
+ const char *
+ GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name);
+
+ static size_t
+ AttachInputReaderCallback (void *baton,
+ lldb_private::InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessGDBRemote only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote);
+
+ lldb_private::unw_addr_space_t
+ GetLibUnwindAddressSpace ();
+
+ void
+ DestoryLibUnwindAddressSpace ();
+};
+
+#endif // liblldb_ProcessGDBRemote_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
new file mode 100644
index 0000000..051ce8f
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -0,0 +1,121 @@
+//===-- ProcessGDBRemoteLog.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessGDBRemoteLog.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+Log *
+ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = g_log;
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+ProcessGDBRemoteLog::DisableLog ()
+{
+ if (g_log)
+ {
+ delete g_log;
+ g_log = NULL;
+ }
+}
+
+Log *
+ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args &args, Stream *feedback_strm)
+{
+ DisableLog ();
+ g_log = new Log (log_stream_sp);
+ if (g_log)
+ {
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ const size_t argc = args.GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *arg = args.GetArgumentAtIndex(i);
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= GDBR_LOG_ALL;
+ else if (::strcasestr (arg, "break") == arg ) flag_bits |= GDBR_LOG_BREAKPOINTS;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= GDBR_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= GDBR_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= GDBR_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= GDBR_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= GDBR_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= GDBR_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= GDBR_LOG_VERBOSE;
+ else if (::strcasestr (arg, "watch") == arg ) flag_bits |= GDBR_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = GDBR_LOG_DEFAULT;
+ g_log->GetMask().SetAllFlagBits(flag_bits);
+ g_log->GetOptions().SetAllFlagBits(log_options);
+ }
+ return g_log;
+}
+
+void
+ProcessGDBRemoteLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for '%s':\n"
+ "\tall - turn on all available logging categories\n"
+ "\tbreak - log breakpoints\n"
+ "\tdefault - enable the default set of logging categories for liblldb\n"
+ "\tpackets - log gdb remote packets\n"
+ "\tmemory - log memory reads and writes\n"
+ "\tdata-short - log memory bytes for memory reads and writes for short transactions only\n"
+ "\tdata-long - log memory bytes for memory reads and writes for all transactions\n"
+ "\tprocess - log process events and activities\n"
+ "\tthread - log thread events and activities\n"
+ "\tstep - log step related activities\n"
+ "\tverbose - enable verbose loggging\n"
+ "\twatch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic());
+}
+
+
+void
+ProcessGDBRemoteLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (mask);
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
new file mode 100644
index 0000000..97580d3
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -0,0 +1,53 @@
+//===-- ProcessGDBRemoteLog.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_ProcessGDBRemoteLog_h_
+#define liblldb_ProcessGDBRemoteLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define GDBR_LOG_VERBOSE (1u << 0)
+#define GDBR_LOG_PROCESS (1u << 1)
+#define GDBR_LOG_THREAD (1u << 2)
+#define GDBR_LOG_PACKETS (1u << 3)
+#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define GDBR_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define GDBR_LOG_BREAKPOINTS (1u << 7)
+#define GDBR_LOG_WATCHPOINTS (1u << 8)
+#define GDBR_LOG_STEP (1u << 9)
+#define GDBR_LOG_COMM (1u << 10)
+#define GDBR_LOG_ALL (UINT32_MAX)
+#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS
+
+class ProcessGDBRemoteLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog ();
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, lldb_private::Args &args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_ProcessGDBRemoteLog_h_
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
new file mode 100644
index 0000000..37485ed
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -0,0 +1,296 @@
+//===-- ThreadGDBRemote.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadGDBRemote.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Breakpoint/WatchpointLocation.h"
+
+#include "LibUnwindRegisterContext.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "StringExtractorGDBRemote.h"
+#include "UnwindLibUnwind.h"
+#include "UnwindMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadGDBRemote::ThreadGDBRemote (ProcessGDBRemote &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_stop_info_stop_id (0),
+ m_stop_info (this),
+ m_thread_name (),
+ m_dispatch_queue_name (),
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS),
+ m_unwinder_ap ()
+{
+// ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD | GDBR_LOG_VERBOSE, "ThreadGDBRemote::ThreadGDBRemote ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID());
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID());
+}
+
+ThreadGDBRemote::~ThreadGDBRemote ()
+{
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID());
+}
+
+
+const char *
+ThreadGDBRemote::GetInfo ()
+{
+ return NULL;
+}
+
+
+const char *
+ThreadGDBRemote::GetName ()
+{
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+
+const char *
+ThreadGDBRemote::GetQueueName ()
+{
+ // Always re-fetch the dispatch queue name since it can change
+ if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ return GetGDBProcess().GetDispatchQueueNameForThread (m_thread_dispatch_qaddr, m_dispatch_queue_name);
+ return NULL;
+}
+
+bool
+ThreadGDBRemote::WillResume (StateType resume_state)
+{
+ // TODO: cache for next time in case we can match things up??
+ ClearStackFrames();
+ int signo = GetResumeSignal();
+ m_stop_info.Clear();
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ case eStateStopped:
+ // Don't append anything for threads that should stay stopped.
+ break;
+
+ case eStateRunning:
+ if (m_process.GetUnixSignals().SignalIsValid (signo))
+ GetGDBProcess().m_continue_packet.Printf(";C%2.2x:%4.4x", signo, GetID());
+ else
+ GetGDBProcess().m_continue_packet.Printf(";c:%4.4x", GetID());
+ break;
+
+ case eStateStepping:
+ if (m_process.GetUnixSignals().SignalIsValid (signo))
+ GetGDBProcess().m_continue_packet.Printf(";S%2.2x:%4.4x", signo, GetID());
+ else
+ GetGDBProcess().m_continue_packet.Printf(";s:%4.4x", GetID());
+ break;
+ }
+ Thread::WillResume(resume_state);
+ return true;
+}
+
+void
+ThreadGDBRemote::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context
+ GetRegisterContext()->Invalidate();
+}
+
+Unwind *
+ThreadGDBRemote::GetUnwinder ()
+{
+ if (m_unwinder_ap.get() == NULL)
+ {
+ const ArchSpec target_arch (GetProcess().GetTarget().GetArchitecture ());
+ if (target_arch == ArchSpec("x86_64") || target_arch == ArchSpec("i386"))
+ {
+ m_unwinder_ap.reset (new UnwindLibUnwind (*this, GetGDBProcess().GetLibUnwindAddressSpace()));
+ }
+ else
+ {
+ m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this));
+ }
+ }
+ return m_unwinder_ap.get();
+}
+
+uint32_t
+ThreadGDBRemote::GetStackFrameCount()
+{
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ return unwinder->GetFrameCount();
+ return 0;
+}
+
+// Make sure that GetStackFrameAtIndex() does NOT call GetStackFrameCount() when
+// getting the stack frame at index zero! This way GetStackFrameCount() (via
+// GetStackFRameData()) can call this function to get the first frame in order
+// to provide the first frame to a lower call for efficiency sake (avoid
+// redundant lookups in the frame symbol context).
+lldb::StackFrameSP
+ThreadGDBRemote::GetStackFrameAtIndex (uint32_t idx)
+{
+
+ StackFrameSP frame_sp (m_frames.GetFrameAtIndex(idx));
+
+ if (frame_sp.get())
+ return frame_sp;
+
+ // Don't try and fetch a frame while process is running
+// FIXME: This check isn't right because IsRunning checks the Public state, but this
+// is work you need to do - for instance in ShouldStop & friends - before the public
+// state has been changed.
+// if (m_process.IsRunning())
+// return frame_sp;
+
+ // Special case the first frame (idx == 0) so that we don't need to
+ // know how many stack frames there are to get it. If we need any other
+ // frames, then we do need to know if "idx" is a valid index.
+ if (idx == 0)
+ {
+ // If this is the first frame, we want to share the thread register
+ // context with the stack frame at index zero.
+ GetRegisterContext();
+ assert (m_reg_context_sp.get());
+ frame_sp.reset (new StackFrame (idx, *this, m_reg_context_sp, m_reg_context_sp->GetSP(), m_reg_context_sp->GetPC()));
+ }
+ else if (idx < GetStackFrameCount())
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ {
+ addr_t pc, cfa;
+ if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
+ frame_sp.reset (new StackFrame (idx, *this, cfa, pc));
+ }
+ }
+ m_frames.SetFrameAtIndex(idx, frame_sp);
+ return frame_sp;
+}
+
+void
+ThreadGDBRemote::ClearStackFrames ()
+{
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ unwinder->Clear();
+ Thread::ClearStackFrames();
+}
+
+
+bool
+ThreadGDBRemote::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadGDBRemote::Dump(Log *log, uint32_t index)
+{
+}
+
+
+bool
+ThreadGDBRemote::ShouldStop (bool &step_more)
+{
+ return true;
+}
+RegisterContext *
+ThreadGDBRemote::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp.reset (CreateRegisterContextForFrame (NULL));
+ return m_reg_context_sp.get();
+}
+
+RegisterContext *
+ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ const bool read_all_registers_at_once = false;
+ uint32_t frame_idx = 0;
+
+ if (frame)
+ frame_idx = frame->GetID();
+
+ if (frame_idx == 0)
+ return new GDBRemoteRegisterContext (*this, frame, GetGDBProcess().m_register_info, read_all_registers_at_once);
+ else if (m_unwinder_ap.get() && frame_idx < m_unwinder_ap->GetFrameCount())
+ return m_unwinder_ap->CreateRegisterContextForFrame (frame);
+ return NULL;
+}
+
+bool
+ThreadGDBRemote::SaveFrameZeroState (RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ checkpoint.SetStackID(frame_sp->GetStackID());
+ return frame_sp->GetRegisterContext()->ReadAllRegisterValues (checkpoint.GetData());
+ }
+ return false;
+}
+
+bool
+ThreadGDBRemote::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ bool ret = frame_sp->GetRegisterContext()->WriteAllRegisterValues (checkpoint.GetData());
+ frame_sp->GetRegisterContext()->Invalidate();
+ ClearStackFrames();
+ return ret;
+ }
+ return false;
+}
+
+bool
+ThreadGDBRemote::GetRawStopReason (StopInfo *stop_info)
+{
+ if (m_stop_info_stop_id != m_process.GetStopID())
+ {
+ char packet[256];
+ const int packet_len = snprintf(packet, sizeof(packet), "qThreadStopInfo%x", GetID());
+ assert (packet_len < (sizeof(packet) - 1));
+ StringExtractorGDBRemote stop_packet;
+ if (GetGDBProcess().GetGDBRemote().SendPacketAndWaitForResponse(packet, stop_packet, 1, false))
+ {
+ std::string copy(stop_packet.GetStringRef());
+ GetGDBProcess().SetThreadStopInfo (stop_packet);
+ // The process should have set the stop info stop ID and also
+ // filled this thread in with valid stop info
+ if (m_stop_info_stop_id != m_process.GetStopID())
+ {
+ //ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "warning: qThreadStopInfo problem: '%s' => '%s'", packet, stop_packet.GetStringRef().c_str());
+ printf("warning: qThreadStopInfo problem: '%s' => '%s'\n\torig '%s'\n", packet, stop_packet.GetStringRef().c_str(), copy.c_str()); /// REMOVE THIS
+ return false;
+ }
+ }
+ }
+ *stop_info = m_stop_info;
+ return true;
+}
+
+
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
new file mode 100644
index 0000000..3fa4ae0
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -0,0 +1,156 @@
+//===-- ThreadGDBRemote.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_ThreadGDBRemote_h_
+#define liblldb_ThreadGDBRemote_h_
+
+#include <string>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "MachException.h"
+#include "libunwind.h"
+
+class StringExtractor;
+class ProcessGDBRemote;
+
+class ThreadGDBRemote : public lldb_private::Thread
+{
+public:
+ ThreadGDBRemote (ProcessGDBRemote &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadGDBRemote ();
+
+ virtual bool
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetInfo ();
+
+ virtual const char *
+ GetName ();
+
+ virtual const char *
+ GetQueueName ();
+
+ virtual lldb_private::RegisterContext *
+ GetRegisterContext ();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ SaveFrameZeroState (RegisterCheckpoint &checkpoint);
+
+ virtual bool
+ RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
+
+ virtual uint32_t
+ GetStackFrameCount();
+
+ virtual lldb::StackFrameSP
+ GetStackFrameAtIndex (uint32_t idx);
+
+ virtual void
+ ClearStackFrames ();
+
+ ProcessGDBRemote &
+ GetGDBProcess ()
+ {
+ return (ProcessGDBRemote &)m_process;
+ }
+
+ const ProcessGDBRemote &
+ GetGDBProcess () const
+ {
+ return (ProcessGDBRemote &)m_process;
+ }
+
+ void
+ Dump (lldb_private::Log *log, uint32_t index);
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ bool
+ ShouldStop (bool &step_more);
+
+ const char *
+ GetBasicInfoAsString ();
+
+ lldb_private::Thread::StopInfo &
+ GetStopInfoRef ()
+ {
+ return m_stop_info;
+ }
+
+ uint32_t
+ GetStopInfoStopID()
+ {
+ return m_stop_info_stop_id;
+ }
+
+ void
+ SetStopInfoStopID (uint32_t stop_id)
+ {
+ m_stop_info_stop_id = stop_id;
+ }
+
+ void
+ SetName (const char *name)
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+ lldb::addr_t
+ GetThreadDispatchQAddr ()
+ {
+ return m_thread_dispatch_qaddr;
+ }
+
+ void
+ SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr)
+ {
+ m_thread_dispatch_qaddr = thread_dispatch_qaddr;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ uint32_t m_stop_info_stop_id;
+ lldb_private::Thread::StopInfo m_stop_info;
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ std::auto_ptr<lldb_private::Unwind> m_unwinder_ap;
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+
+ lldb_private::Unwind *
+ GetUnwinder ();
+
+ void
+ SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id);
+
+ virtual bool
+ GetRawStopReason (StopInfo *stop_info);
+
+
+};
+
+#endif // liblldb_ThreadGDBRemote_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
new file mode 100644
index 0000000..989e494
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -0,0 +1,211 @@
+//===-- DWARFAbbreviationDeclaration.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFAbbreviationDeclaration.h"
+
+#include "lldb/Core/dwarf.h"
+
+#include "DWARFFormValue.h"
+
+using namespace lldb_private;
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() :
+ m_code (InvalidCode),
+ m_tag (0),
+ m_has_children (0),
+ m_attributes()
+{
+}
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children) :
+ m_code (InvalidCode),
+ m_tag (tag),
+ m_has_children (has_children),
+ m_attributes()
+{
+}
+
+bool
+DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, uint32_t* offset_ptr)
+{
+ return Extract(data, offset_ptr, data.GetULEB128(offset_ptr));
+}
+
+bool
+DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, uint32_t* offset_ptr, dw_uleb128_t code)
+{
+ m_code = code;
+ m_attributes.clear();
+ if (m_code)
+ {
+ m_tag = data.GetULEB128(offset_ptr);
+ m_has_children = data.GetU8(offset_ptr);
+
+ while (data.ValidOffset(*offset_ptr))
+ {
+ dw_attr_t attr = data.GetULEB128(offset_ptr);
+ dw_form_t form = data.GetULEB128(offset_ptr);
+
+ if (attr && form)
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ else
+ break;
+ }
+
+ return m_tag != 0;
+ }
+ else
+ {
+ m_tag = 0;
+ m_has_children = 0;
+ }
+
+ return false;
+}
+
+
+void
+DWARFAbbreviationDeclaration::Dump(Stream *s) const
+{
+// *ostrm_ptr << std::setfill(' ') << std::dec << '[' << std::setw(3) << std::right << m_code << ']' << ' ' << std::setw(30) << std::left << DW_TAG_value_to_name(m_tag) << DW_CHILDREN_value_to_name(m_has_children) << std::endl;
+//
+// DWARFAttribute::const_iterator pos;
+//
+// for (pos = m_attributes.begin(); pos != m_attributes.end(); ++pos)
+// *ostrm_ptr << " " << std::setw(29) << std::left << DW_AT_value_to_name(pos->attr()) << ' ' << DW_FORM_value_to_name(pos->form()) << std::endl;
+//
+// *ostrm_ptr << std::endl;
+}
+
+
+
+bool
+DWARFAbbreviationDeclaration::IsValid()
+{
+ return m_code != 0 && m_tag != 0;
+}
+
+
+void
+DWARFAbbreviationDeclaration::CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx)
+{
+ m_code = abbr_decl.Code(); // Invalidate the code since that can't be copied safely.
+ m_tag = abbr_decl.Tag();
+ m_has_children = abbr_decl.HasChildren();
+
+ const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
+ const uint32_t num_abbr_decl_attributes = attributes.size();
+
+ dw_attr_t attr;
+ dw_form_t form;
+ uint32_t i;
+
+ for (i = 0; i < num_abbr_decl_attributes; ++i)
+ {
+ attributes[i].get(attr, form);
+ switch (attr)
+ {
+ case DW_AT_location:
+ case DW_AT_frame_base:
+ // Only add these if they are location expressions (have a single
+ // value) and not location lists (have a lists of location
+ // expressions which are only valid over specific address ranges)
+ if (DWARFFormValue::IsBlockForm(form))
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ case DW_AT_ranges:
+ case DW_AT_entry_pc:
+ // Don't add these attributes
+ if (i >= idx)
+ break;
+ // Fall through and add attribute
+ default:
+ // Add anything that isn't address related
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ break;
+ }
+ }
+}
+
+void
+DWARFAbbreviationDeclaration::CopyChangingStringToStrp(
+ const DWARFAbbreviationDeclaration& abbr_decl,
+ const DataExtractor& debug_info_data,
+ dw_offset_t debug_info_offset,
+ const DWARFCompileUnit* cu,
+ const uint32_t strp_min_len
+)
+{
+ m_code = InvalidCode;
+ m_tag = abbr_decl.Tag();
+ m_has_children = abbr_decl.HasChildren();
+
+ const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
+ const uint32_t num_abbr_decl_attributes = attributes.size();
+
+ dw_attr_t attr;
+ dw_form_t form;
+ uint32_t i;
+ dw_offset_t offset = debug_info_offset;
+
+ for (i = 0; i < num_abbr_decl_attributes; ++i)
+ {
+ attributes[i].get(attr, form);
+ dw_offset_t attr_offset = offset;
+ DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu);
+
+ if (form == DW_FORM_string && ((offset - attr_offset) >= strp_min_len))
+ m_attributes.push_back(DWARFAttribute(attr, DW_FORM_strp));
+ else
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ }
+}
+
+
+uint32_t
+DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const
+{
+ uint32_t i;
+ const uint32_t kNumAttributes = m_attributes.size();
+ for (i = 0; i < kNumAttributes; ++i)
+ {
+ if (m_attributes[i].get_attr() == attr)
+ return i;
+ }
+ return DW_INVALID_INDEX;
+}
+
+
+bool
+DWARFAbbreviationDeclaration::operator == (const DWARFAbbreviationDeclaration& rhs) const
+{
+ return Tag() == rhs.Tag()
+ && HasChildren() == rhs.HasChildren()
+ && Attributes() == rhs.Attributes();
+}
+
+#if 0
+DWARFAbbreviationDeclaration::Append(BinaryStreamBuf& out_buff) const
+{
+ out_buff.Append32_as_ULEB128(Code());
+ out_buff.Append32_as_ULEB128(Tag());
+ out_buff.Append8(HasChildren());
+ const uint32_t kNumAttributes = m_attributes.size();
+ for (uint32_t i = 0; i < kNumAttributes; ++i)
+ {
+ out_buff.Append32_as_ULEB128(m_attributes[i].attr());
+ out_buff.Append32_as_ULEB128(m_attributes[i].form());
+ }
+ out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
+ out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
+}
+#endif // 0
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
new file mode 100644
index 0000000..7959f26
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
@@ -0,0 +1,77 @@
+//===-- DWARFAbbreviationDeclaration.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_DWARFAbbreviationDeclaration_h_
+#define liblldb_DWARFAbbreviationDeclaration_h_
+
+#include "SymbolFileDWARF.h"
+#include "DWARFAttribute.h"
+
+class DWARFCompileUnit;
+
+class DWARFAbbreviationDeclaration
+{
+public:
+ enum { InvalidCode = 0 };
+ DWARFAbbreviationDeclaration();
+
+ // For hand crafting an abbreviation declaration
+ DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children);
+ void AddAttribute(const DWARFAttribute& attr)
+ {
+ m_attributes.push_back(attr);
+ }
+
+ dw_uleb128_t Code() const { return m_code; }
+ void SetCode(dw_uleb128_t code) { m_code = code; }
+ dw_tag_t Tag() const { return m_tag; }
+ bool HasChildren() const { return m_has_children; }
+ uint32_t NumAttributes() const { return m_attributes.size(); }
+ dw_attr_t GetAttrByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_attr() : 0; }
+ dw_form_t GetFormByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_form() : 0; }
+ bool GetAttrAndFormByIndex(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const
+ {
+ if (m_attributes.size() > idx)
+ {
+ m_attributes[idx].get(attr, form);
+ return true;
+ }
+ attr = form = 0;
+ return false;
+ }
+
+ // idx is assumed to be valid when calling GetAttrAndFormByIndexUnchecked()
+ void GetAttrAndFormByIndexUnchecked(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const
+ {
+ m_attributes[idx].get(attr, form);
+ }
+ void CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx);
+ void CopyChangingStringToStrp(
+ const DWARFAbbreviationDeclaration& abbr_decl,
+ const lldb_private::DataExtractor& debug_info_data,
+ dw_offset_t debug_info_offset,
+ const DWARFCompileUnit* cu,
+ const uint32_t strp_min_len);
+ uint32_t FindAttributeIndex(dw_attr_t attr) const;
+ bool Extract(const lldb_private::DataExtractor& data, uint32_t* offset_ptr);
+ bool Extract(const lldb_private::DataExtractor& data, uint32_t* offset_ptr, dw_uleb128_t code);
+// void Append(BinaryStreamBuf& out_buff) const;
+ bool IsValid();
+ void Dump(lldb_private::Stream *s) const;
+ bool operator == (const DWARFAbbreviationDeclaration& rhs) const;
+// DWARFAttribute::collection& Attributes() { return m_attributes; }
+ const DWARFAttribute::collection& Attributes() const { return m_attributes; }
+protected:
+ dw_uleb128_t m_code;
+ dw_tag_t m_tag;
+ uint8_t m_has_children;
+ DWARFAttribute::collection m_attributes;
+};
+
+#endif // liblldb_DWARFAbbreviationDeclaration_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
new file mode 100644
index 0000000..0b44926
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
@@ -0,0 +1,45 @@
+//===-- DWARFAttribute.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_DWARFAttribute_h_
+#define liblldb_DWARFAttribute_h_
+
+#include "DWARFDefines.h"
+#include <vector>
+
+class DWARFAttribute
+{
+public:
+ DWARFAttribute(dw_attr_t attr, dw_form_t form) :
+ m_attr_form ( attr << 16 | form )
+ {
+ }
+
+ void set(dw_attr_t attr, dw_form_t form) { m_attr_form = (attr << 16) | form; }
+ void set_attr(dw_attr_t attr) { m_attr_form = (m_attr_form & 0x0000ffffu) | (attr << 16); }
+ void set_form(dw_form_t form) { m_attr_form = (m_attr_form & 0xffff0000u) | form; }
+ dw_attr_t get_attr() const { return m_attr_form >> 16; }
+ dw_form_t get_form() const { return m_attr_form; }
+ void get(dw_attr_t& attr, dw_form_t& form) const
+ {
+ register uint32_t attr_form = m_attr_form;
+ attr = attr_form >> 16;
+ form = attr_form;
+ }
+ bool operator == (const DWARFAttribute& rhs) const { return m_attr_form == rhs.m_attr_form; }
+ typedef std::vector<DWARFAttribute> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+protected:
+ uint32_t m_attr_form; // Upper 16 bits is attribute, lower 16 bits is form
+};
+
+
+#endif // liblldb_DWARFAttribute_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 0000000..e7f92c6
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,770 @@
+//===-- DWARFCompileUnit.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFCompileUnit.h"
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+using namespace std;
+
+extern int g_verbose;
+
+DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* m_dwarf2Data) :
+ m_dwarf2Data ( m_dwarf2Data ),
+ m_offset ( DW_INVALID_OFFSET ),
+ m_length ( 0 ),
+ m_version ( 0 ),
+ m_abbrevs ( NULL ),
+ m_addr_size ( DWARFCompileUnit::GetDefaultAddressSize() ),
+ m_base_addr ( 0 ),
+ m_die_array (),
+ m_aranges_ap (),
+ m_user_data ( NULL )
+{
+}
+
+void
+DWARFCompileUnit::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_length = 0;
+ m_version = 0;
+ m_abbrevs = NULL;
+ m_addr_size = DWARFCompileUnit::GetDefaultAddressSize();
+ m_base_addr = 0;
+ m_die_array.clear();
+ m_aranges_ap.reset();
+ m_user_data = NULL;
+}
+
+bool
+DWARFCompileUnit::Extract(const DataExtractor &debug_info, uint32_t* offset_ptr)
+{
+ Clear();
+
+ m_offset = *offset_ptr;
+
+ if (debug_info.ValidOffset(*offset_ptr))
+ {
+ dw_offset_t abbr_offset;
+ const DWARFDebugAbbrev *abbr = m_dwarf2Data->DebugAbbrev();
+ m_length = debug_info.GetU32(offset_ptr);
+ m_version = debug_info.GetU16(offset_ptr);
+ abbr_offset = debug_info.GetU32(offset_ptr);
+ m_addr_size = debug_info.GetU8 (offset_ptr);
+
+ bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1);
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset);
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+
+ if (length_OK && version_OK && addr_size_OK && abbr_offset_OK && abbr != NULL)
+ {
+ m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset);
+ return true;
+ }
+
+ // reset the offset to where we tried to parse from if anything went wrong
+ *offset_ptr = m_offset;
+ }
+
+ return false;
+}
+
+
+dw_offset_t
+DWARFCompileUnit::Extract(dw_offset_t offset, const DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs)
+{
+ Clear();
+
+ m_offset = offset;
+
+ if (debug_info_data.ValidOffset(offset))
+ {
+ m_length = debug_info_data.GetU32(&offset);
+ m_version = debug_info_data.GetU16(&offset);
+ bool abbrevs_OK = debug_info_data.GetU32(&offset) == abbrevs->GetOffset();
+ m_abbrevs = abbrevs;
+ m_addr_size = debug_info_data.GetU8 (&offset);
+
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+
+ if (version_OK && addr_size_OK && abbrevs_OK && debug_info_data.ValidOffset(offset))
+ return offset;
+ }
+ return DW_INVALID_OFFSET;
+}
+
+void
+DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die)
+{
+ if (m_die_array.size() > 1)
+ {
+ // std::vectors never get any smaller when resized to a smaller size,
+ // or when clear() or erase() are called, the size will report that it
+ // is smaller, but the memory allocated remains intact (call capacity()
+ // to see this). So we need to create a temporary vector and swap the
+ // contents which will cause just the internal pointers to be swapped
+ // so that when "tmp_array" goes out of scope, it will destroy the
+ // contents.
+
+ // Save at least the compile unit DIE
+ DWARFDebugInfoEntry::collection tmp_array;
+ m_die_array.swap(tmp_array);
+ if (keep_compile_unit_die)
+ m_die_array.push_back(tmp_array.front());
+ }
+}
+
+//----------------------------------------------------------------------
+// ParseCompileUnitDIEsIfNeeded
+//
+// Parses a compile unit and indexes its DIEs if it already hasn't been
+// done.
+//----------------------------------------------------------------------
+size_t
+DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only)
+{
+ const size_t initial_die_array_size = m_die_array.size();
+ if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1)
+ return 0; // Already parsed
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )",
+ m_offset,
+ cu_die_only);
+
+ // Set the offset to that of the first DIE
+ uint32_t offset = GetFirstDIEOffset();
+ const dw_offset_t next_cu_offset = GetNextCompileUnitOffset();
+ DWARFDebugInfoEntry die;
+ // Keep a flat array of the DIE for binary lookup by DIE offset
+ Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO);
+// if (log)
+// log->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, abbr_offset = 0x%8.8x, addr_size = 0x%2.2x",
+// cu->GetOffset(),
+// cu->GetLength(),
+// cu->GetVersion(),
+// cu->GetAbbrevOffset(),
+// cu->GetAddressByteSize());
+
+ uint32_t depth = 0;
+ // We are in our compile unit, parse starting at the offset
+ // we were told to parse
+ while (die.Extract(m_dwarf2Data, this, &offset))
+ {
+ if (log)
+ log->Printf("0x%8.8x: %*.*s%s%s",
+ die.GetOffset(),
+ depth * 2, depth * 2, "",
+ DW_TAG_value_to_name (die.Tag()),
+ die.HasChildren() ? " *" : "");
+ if (cu_die_only)
+ {
+ AddDIE(die);
+ return 1;
+ }
+ else if (depth == 0 && initial_die_array_size == 1)
+ {
+ // Don't append the CU die as we already did that
+ }
+ else
+ {
+ AddDIE(die);
+ }
+
+ const DWARFAbbreviationDeclaration* abbrDecl = die.GetAbbreviationDeclarationPtr();
+ if (abbrDecl)
+ {
+ // Normal DIE
+ if (abbrDecl->HasChildren())
+ ++depth;
+ }
+ else
+ {
+ // NULL DIE.
+ if (depth > 0)
+ --depth;
+ else
+ break; // We are done with this compile unit!
+ }
+
+ assert(offset <= next_cu_offset);
+ }
+ SetDIERelations();
+ return m_die_array.size();
+}
+
+
+dw_offset_t
+DWARFCompileUnit::GetAbbrevOffset() const
+{
+ return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET;
+}
+
+
+
+bool
+DWARFCompileUnit::Verify(Stream *s) const
+{
+ const DataExtractor& debug_info = m_dwarf2Data->get_debug_info_data();
+ bool valid_offset = debug_info.ValidOffset(m_offset);
+ bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1);
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset());
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+ bool verbose = s->GetVerbose();
+ if (valid_offset && length_OK && version_OK && addr_size_OK && abbr_offset_OK)
+ {
+ if (verbose)
+ s->Printf(" 0x%8.8x: OK\n", m_offset);
+ return true;
+ }
+ else
+ {
+ s->Printf(" 0x%8.8x: ", m_offset);
+
+ m_dwarf2Data->get_debug_info_data().Dump (s, m_offset, lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, 0);
+ s->EOL();
+ if (valid_offset)
+ {
+ if (!length_OK)
+ s->Printf(" The length (0x%8.8x) for this compile unit is too large for the .debug_info provided.\n", m_length);
+ if (!version_OK)
+ s->Printf(" The 16 bit compile unit header version is not supported.\n");
+ if (!abbr_offset_OK)
+ s->Printf(" The offset into the .debug_abbrev section (0x%8.8x) is not valid.\n", GetAbbrevOffset());
+ if (!addr_size_OK)
+ s->Printf(" The address size is unsupported: 0x%2.2x\n", m_addr_size);
+ }
+ else
+ s->Printf(" The start offset of the compile unit header in the .debug_info is invalid.\n");
+ }
+ return false;
+}
+
+
+void
+DWARFCompileUnit::Dump(Stream *s) const
+{
+ s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at {0x%8.8x})\n",
+ m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, GetNextCompileUnitOffset());
+}
+
+
+static uint8_t g_default_addr_size = 4;
+
+uint8_t
+DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit* cu)
+{
+ if (cu)
+ return cu->GetAddressByteSize();
+ return DWARFCompileUnit::GetDefaultAddressSize();
+}
+
+uint8_t
+DWARFCompileUnit::GetDefaultAddressSize()
+{
+ return g_default_addr_size;
+}
+
+void
+DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size)
+{
+ g_default_addr_size = addr_size;
+}
+
+bool
+DWARFCompileUnit::LookupAddress
+(
+ const dw_addr_t address,
+ DWARFDebugInfoEntry** function_die_handle,
+ DWARFDebugInfoEntry** block_die_handle
+)
+{
+ bool success = false;
+
+ if (function_die_handle != NULL && DIE())
+ {
+ if (m_aranges_ap.get() == NULL)
+ {
+ m_aranges_ap.reset(new DWARFDebugAranges());
+ m_die_array.front().BuildFunctionAddressRangeTable(m_dwarf2Data, this, m_aranges_ap.get());
+ }
+
+ // Re-check the aranges auto pointer contents in case it was created above
+ if (m_aranges_ap.get() != NULL)
+ {
+ *function_die_handle = GetDIEPtr(m_aranges_ap->FindAddress(address));
+ if (*function_die_handle != NULL)
+ {
+ success = true;
+ if (block_die_handle != NULL)
+ {
+ DWARFDebugInfoEntry* child = (*function_die_handle)->GetFirstChild();
+ while (child)
+ {
+ if (child->LookupAddress(address, m_dwarf2Data, this, NULL, block_die_handle))
+ break;
+ child = child->GetSibling();
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+//----------------------------------------------------------------------
+// SetDIERelations()
+//
+// We read in all of the DIE entries into our flat list of DIE entries
+// and now we need to go back through all of them and set the parent,
+// sibling and child pointers for quick DIE navigation.
+//----------------------------------------------------------------------
+void
+DWARFCompileUnit::SetDIERelations()
+{
+#if 0
+ // Compute average bytes per DIE
+ //
+ // We can figure out what the average number of bytes per DIE is
+ // to help us pre-allocate the correct number of m_die_array
+ // entries so we don't end up doing a lot of memory copies as we
+ // are creating our DIE array when parsing
+ //
+ // Enable this code by changing "#if 0" above to "#if 1" and running
+ // the dsymutil or dwarfdump with a bunch of dwarf files and see what
+ // the running average ends up being in the stdout log.
+ static size_t g_total_cu_debug_info_size = 0;
+ static size_t g_total_num_dies = 0;
+ static size_t g_min_bytes_per_die = UINT_MAX;
+ static size_t g_max_bytes_per_die = 0;
+ const size_t num_dies = m_die_array.size();
+ const size_t cu_debug_info_size = GetDebugInfoSize();
+ const size_t bytes_per_die = cu_debug_info_size / num_dies;
+ if (g_min_bytes_per_die > bytes_per_die)
+ g_min_bytes_per_die = bytes_per_die;
+ if (g_max_bytes_per_die < bytes_per_die)
+ g_max_bytes_per_die = bytes_per_die;
+ if (g_total_cu_debug_info_size == 0)
+ {
+ cout << " min max avg" << endl
+ << "n dies cu size bpd bpd bpd bpd" << endl
+ << "------ -------- --- === === ===" << endl;
+ }
+ g_total_cu_debug_info_size += cu_debug_info_size;
+ g_total_num_dies += num_dies;
+ const size_t avg_bytes_per_die = g_total_cu_debug_info_size / g_total_num_dies;
+ cout
+ << DECIMAL_WIDTH(6) << num_dies << ' '
+ << DECIMAL_WIDTH(8) << cu_debug_info_size << ' '
+ << DECIMAL_WIDTH(3) << bytes_per_die << ' '
+ << DECIMAL_WIDTH(3) << g_min_bytes_per_die << ' '
+ << DECIMAL_WIDTH(3) << g_max_bytes_per_die << ' '
+ << DECIMAL_WIDTH(3) << avg_bytes_per_die
+ << endl;
+#endif
+ if (m_die_array.empty())
+ return;
+ DWARFDebugInfoEntry* die_array_begin = &m_die_array.front();
+ DWARFDebugInfoEntry* die_array_end = &m_die_array.back();
+ DWARFDebugInfoEntry* curr_die;
+ // We purposely are skipping the last element in the array in the loop below
+ // so that we can always have a valid next item
+ for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die)
+ {
+ // Since our loop doesn't include the last element, we can always
+ // safely access the next die in the array.
+ DWARFDebugInfoEntry* next_die = curr_die + 1;
+
+ const DWARFAbbreviationDeclaration* curr_die_abbrev = curr_die->GetAbbreviationDeclarationPtr();
+
+ if (curr_die_abbrev)
+ {
+ // Normal DIE
+ if (curr_die_abbrev->HasChildren())
+ next_die->SetParent(curr_die);
+ else
+ curr_die->SetSibling(next_die);
+ }
+ else
+ {
+ // NULL DIE that terminates a sibling chain
+ DWARFDebugInfoEntry* parent = curr_die->GetParent();
+ if (parent)
+ parent->SetSibling(next_die);
+ }
+ }
+
+ // Since we skipped the last element, we need to fix it up!
+ if (die_array_begin < die_array_end)
+ curr_die->SetParent(die_array_begin);
+
+#if 0
+ // The code below will dump the DIE relations in case any modification
+ // is done to the above code. This dump can be used in a diff to make
+ // sure that no functionality is lost.
+ {
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ puts("offset parent sibling child");
+ puts("-------- -------- -------- --------");
+ for (pos = m_die_array.begin(); pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry& die_ref = *pos;
+ const DWARFDebugInfoEntry* p = die_ref.GetParent();
+ const DWARFDebugInfoEntry* s = die_ref.GetSibling();
+ const DWARFDebugInfoEntry* c = die_ref.GetFirstChild();
+ printf("%.8x: %.8x %.8x %.8x\n", die_ref.GetOffset(),
+ p ? p->GetOffset() : 0,
+ s ? s->GetOffset() : 0,
+ c ? c->GetOffset() : 0);
+ }
+ }
+#endif
+
+}
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
+{
+ return die1.GetOffset() < die2.GetOffset();
+}
+
+//----------------------------------------------------------------------
+// GetDIEPtr()
+//
+// Get the DIE (Debug Information Entry) with the specified offset.
+//----------------------------------------------------------------------
+DWARFDebugInfoEntry*
+DWARFCompileUnit::GetDIEPtr(dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ExtractDIEsIfNeeded (false);
+ DWARFDebugInfoEntry compare_die;
+ compare_die.SetOffset(die_offset);
+ DWARFDebugInfoEntry::iterator end = m_die_array.end();
+ DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset);
+ if (pos != end)
+ {
+ if (die_offset == (*pos).GetOffset())
+ return &(*pos);
+ }
+ }
+ return NULL; // Not found in any compile units
+}
+
+//----------------------------------------------------------------------
+// GetDIEPtrContainingOffset()
+//
+// Get the DIE (Debug Information Entry) that contains the specified
+// .debug_info offset.
+//----------------------------------------------------------------------
+const DWARFDebugInfoEntry*
+DWARFCompileUnit::GetDIEPtrContainingOffset(dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ExtractDIEsIfNeeded (false);
+ DWARFDebugInfoEntry compare_die;
+ compare_die.SetOffset(die_offset);
+ DWARFDebugInfoEntry::iterator end = m_die_array.end();
+ DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset);
+ if (pos != end)
+ {
+ if (die_offset >= (*pos).GetOffset())
+ {
+ DWARFDebugInfoEntry::iterator next = pos + 1;
+ if (next != end)
+ {
+ if (die_offset < (*next).GetOffset())
+ return &(*pos);
+ }
+ }
+ }
+ }
+ return NULL; // Not found in any compile units
+}
+
+
+
+size_t
+DWARFCompileUnit::AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& dies, uint32_t depth) const
+{
+ size_t old_size = dies.Size();
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ for (pos = m_die_array.begin(); pos != end; ++pos)
+ {
+ if (pos->Tag() == tag)
+ dies.Insert(&(*pos));
+ }
+
+ // Return the number of DIEs added to the collection
+ return dies.Size() - old_size;
+}
+
+void
+DWARFCompileUnit::AddGlobalDIEByIndex (uint32_t die_idx)
+{
+ m_global_die_indexes.push_back (die_idx);
+}
+
+
+void
+DWARFCompileUnit::AddGlobal (const DWARFDebugInfoEntry* die)
+{
+ // Indexes to all file level global and static variables
+ m_global_die_indexes;
+
+ if (m_die_array.empty())
+ return;
+
+ const DWARFDebugInfoEntry* first_die = &m_die_array[0];
+ const DWARFDebugInfoEntry* end = first_die + m_die_array.size();
+ if (first_die <= die && die < end)
+ m_global_die_indexes.push_back (die - first_die);
+}
+
+
+void
+DWARFCompileUnit::Index
+(
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_function_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_inlined_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_global_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_type_die
+)
+{
+
+ const DataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data();
+
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator begin = m_die_array.begin();
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry &die = *pos;
+
+ const dw_tag_t tag = die.Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_typedef:
+ case DW_TAG_namespace:
+ case DW_TAG_variable:
+ break;
+
+ default:
+ continue;
+ }
+
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ bool is_variable = false;
+ bool is_declaration = false;
+ bool is_artificial = false;
+ bool has_address = false;
+ bool has_location = false;
+ bool is_global_or_static_variable = false;
+ const size_t num_attributes = die.GetAttributes(m_dwarf2Data, this, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ dw_tag_t tag = die.Tag();
+
+ is_variable = tag == DW_TAG_variable;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ name = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_declaration:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ is_declaration = form_value.Unsigned() != 0;
+ break;
+
+ case DW_AT_artificial:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ is_artificial = form_value.Unsigned() != 0;
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ mangled = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_ranges:
+ case DW_AT_entry_pc:
+ has_address = true;
+ break;
+
+ case DW_AT_location:
+ has_location = true;
+ if (tag == DW_TAG_variable)
+ {
+ const DWARFDebugInfoEntry* parent_die = die.GetParent();
+ while ( parent_die != NULL )
+ {
+ switch (parent_die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ // Even if this is a function level static, we don't add it. We could theoretically
+ // add these if we wanted to by introspecting into the DW_AT_location and seeing
+ // if the location describes a hard coded address, but we dont want the performance
+ // penalty of that right now.
+ is_global_or_static_variable = false;
+// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+// {
+// // If we have valid block data, then we have location expression bytes
+// // that are fixed (not a location list).
+// const uint8_t *block_data = form_value.BlockData();
+// if (block_data)
+// {
+// uint32_t block_length = form_value.Unsigned();
+// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
+// {
+// if (block_data[0] == DW_OP_addr)
+// add_die = true;
+// }
+// }
+// }
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ case DW_TAG_compile_unit:
+ is_global_or_static_variable = true;
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ default:
+ parent_die = parent_die->GetParent(); // Keep going in the while loop.
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ if (has_address)
+ {
+ if (name && name[0])
+ {
+ if ((name[0] == '-' || name[0] == '+') && name[1] == '[')
+ {
+ int name_len = strlen (name);
+ // Objective C methods must have at least:
+ // "-[" or "+[" prefix
+ // One character for a class name
+ // One character for the space between the class name
+ // One character for the method name
+ // "]" suffix
+ if (name_len >= 6 && name[name_len - 1] == ']')
+ {
+ const char *method_name = strchr (name, ' ');
+ if (method_name)
+ {
+ // Skip the space
+ ++method_name;
+ // Extract the objective C basename and add it to the
+ // accelerator tables
+ size_t method_name_len = name_len - (method_name - name) - 1;
+ ConstString method_const_str (method_name, method_name_len);
+ name_to_function_die.Append(method_const_str.AsCString(), die.GetOffset());
+ }
+ }
+ }
+ name_to_function_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ }
+ if (mangled && mangled[0])
+ name_to_function_die.Append(ConstString(mangled).AsCString(), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_inlined_subroutine:
+ if (has_address)
+ {
+ if (name && name[0])
+ name_to_inlined_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ if (mangled && mangled[0])
+ name_to_inlined_die.Append(ConstString(mangled).AsCString(), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_typedef:
+ case DW_TAG_namespace:
+ if (name && is_declaration == false)
+ {
+ name_to_type_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_variable:
+ if (name && has_location && is_global_or_static_variable)
+ {
+ AddGlobalDIEByIndex (std::distance (begin, pos));
+ name_to_global_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+}
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
new file mode 100644
index 0000000..44bbbfe
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -0,0 +1,168 @@
+//===-- DWARFCompileUnit.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_DWARFCompileUnit_h_
+#define SymbolFileDWARF_DWARFCompileUnit_h_
+
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugInfoEntry.h"
+
+class DWARFCompileUnit
+{
+public:
+ DWARFCompileUnit(SymbolFileDWARF* dwarf2Data);
+
+ bool Extract(const lldb_private::DataExtractor &debug_info, uint32_t* offset_ptr);
+ dw_offset_t Extract(dw_offset_t offset, const lldb_private::DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs);
+ size_t ExtractDIEsIfNeeded (bool cu_die_only);
+ bool LookupAddress(
+ const dw_addr_t address,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ size_t AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& matching_dies, uint32_t depth = UINT_MAX) const;
+ void Clear();
+ bool Verify(lldb_private::Stream *s) const;
+ void Dump(lldb_private::Stream *s) const;
+ dw_offset_t GetOffset() const { return m_offset; }
+ uint32_t Size() const { return 11; /* Size in bytes of the compile unit header */ }
+ bool ContainsDIEOffset(dw_offset_t die_offset) const { return die_offset >= GetFirstDIEOffset() && die_offset < GetNextCompileUnitOffset(); }
+ dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); }
+ dw_offset_t GetNextCompileUnitOffset() const { return m_offset + m_length + 4; }
+ size_t GetDebugInfoSize() const { return m_length + 4 - Size(); /* Size in bytes of the .debug_info data associated with this compile unit. */ }
+ uint32_t GetLength() const { return m_length; }
+ uint16_t GetVersion() const { return m_version; }
+ const DWARFAbbreviationDeclarationSet* GetAbbreviations() const { return m_abbrevs; }
+ dw_offset_t GetAbbrevOffset() const;
+ uint8_t GetAddressByteSize() const { return m_addr_size; }
+ dw_addr_t GetBaseAddress() const { return m_base_addr; }
+ void ClearDIEs(bool keep_compile_unit_die);
+
+ void
+ SetBaseAddress(dw_addr_t base_addr)
+ {
+ m_base_addr = base_addr;
+ }
+
+ void
+ SetDIERelations();
+
+ const DWARFDebugInfoEntry*
+ GetCompileUnitDIEOnly()
+ {
+ ExtractDIEsIfNeeded (true);
+ if (m_die_array.empty())
+ return NULL;
+ return &m_die_array[0];
+ }
+
+ const DWARFDebugInfoEntry*
+ DIE()
+ {
+ ExtractDIEsIfNeeded (false);
+ if (m_die_array.empty())
+ return NULL;
+ return &m_die_array[0];
+ }
+
+ void
+ AddDIE(DWARFDebugInfoEntry& die)
+ {
+ // The average bytes per DIE entry has been seen to be
+ // around 14-20 so lets pre-reserve the needed memory for
+ // our DIE entries accordingly. Search forward for "Compute
+ // average bytes per DIE" to see #if'ed out code that does
+ // that determination.
+
+ // Only reserve the memory if we are adding children of
+ // the main compile unit DIE. The compile unit DIE is always
+ // the first entry, so if our size is 1, then we are adding
+ // the first compile unit child DIE and should reserve
+ // the memory.
+ if (m_die_array.empty())
+ m_die_array.reserve(GetDebugInfoSize() / 14);
+ m_die_array.push_back(die);
+ }
+
+ DWARFDebugInfoEntry*
+ GetDIEPtr (dw_offset_t die_offset);
+
+ const DWARFDebugInfoEntry*
+ GetDIEPtrContainingOffset (dw_offset_t die_offset);
+
+ static uint8_t
+ GetAddressByteSize(const DWARFCompileUnit* cu);
+
+ static uint8_t
+ GetDefaultAddressSize();
+ static void
+ SetDefaultAddressSize(uint8_t addr_size);
+
+ void *
+ GetUserData() const
+ {
+ return m_user_data;
+ }
+
+ void
+ SetUserData(void *d)
+ {
+ m_user_data = d;
+ }
+
+
+ void
+ AddGlobalDIEByIndex (uint32_t die_idx);
+
+ void
+ AddGlobal (const DWARFDebugInfoEntry* die);
+
+ size_t
+ GetNumGlobals () const
+ {
+ return m_global_die_indexes.size();
+ }
+
+ const DWARFDebugInfoEntry *
+ GetGlobalDIEAtIndex (uint32_t idx)
+ {
+ if (idx < m_global_die_indexes.size())
+ {
+ uint32_t die_idx = m_global_die_indexes[idx];
+ if (die_idx < m_die_array.size())
+ return &m_die_array[die_idx];
+ }
+ return NULL;
+ }
+
+ void
+ Index (lldb_private::UniqueCStringMap<dw_offset_t>& name_to_function_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_inlined_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_global_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_type_die);
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ dw_offset_t m_offset;
+ uint32_t m_length;
+ uint16_t m_version;
+ const DWARFAbbreviationDeclarationSet*
+ m_abbrevs;
+ uint8_t m_addr_size;
+ dw_addr_t m_base_addr;
+ DWARFDebugInfoEntry::collection
+ m_die_array; // The compile unit debug information entry item
+ std::auto_ptr<DWARFDebugAranges> m_aranges_ap; // A table similar to the .debug_aranges table, but this one points to the exact DW_TAG_subprogram DIEs
+ std::vector<uint32_t> m_global_die_indexes; // Indexes to all file level global and static variables
+ void * m_user_data;
+private:
+ DISALLOW_COPY_AND_ASSIGN (DWARFCompileUnit);
+};
+
+#endif // SymbolFileDWARF_DWARFCompileUnit_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
new file mode 100644
index 0000000..60aac74
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
@@ -0,0 +1,56 @@
+//===-- DWARFDIECollection.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDIECollection.h"
+
+#include <algorithm>
+
+#include "lldb/Core/Stream.h"
+
+#include "DWARFDebugInfoEntry.h"
+
+using namespace lldb_private;
+using namespace std;
+
+bool
+DWARFDIECollection::Insert(const DWARFDebugInfoEntry *die)
+{
+ iterator end_pos = m_dies.end();
+ iterator insert_pos = upper_bound(m_dies.begin(), end_pos, die);
+ if (insert_pos != end_pos && (*insert_pos == die))
+ return false;
+ m_dies.insert(insert_pos, die);
+ return true;
+}
+
+const DWARFDebugInfoEntry *
+DWARFDIECollection::GetDIEPtrAtIndex(uint32_t idx) const
+{
+ if (idx < m_dies.size())
+ return m_dies[idx];
+ return NULL;
+}
+
+
+size_t
+DWARFDIECollection::Size() const
+{
+ return m_dies.size();
+}
+
+void
+DWARFDIECollection::Dump(Stream *s, const char* title) const
+{
+ if (title && title[0] != '\0')
+ s->Printf( "%s\n", title);
+ const_iterator end_pos = m_dies.end();
+ const_iterator pos;
+ for (pos = m_dies.begin(); pos != end_pos; ++pos)
+ s->Printf( "0x%8.8x\n", (*pos)->GetOffset());
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
new file mode 100644
index 0000000..c374a14
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
@@ -0,0 +1,48 @@
+//===-- DWARFDIECollection.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_DWARFDIECollection_h_
+#define SymbolFileDWARF_DWARFDIECollection_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class DWARFDIECollection
+{
+public:
+ DWARFDIECollection() :
+ m_dies()
+ {
+ }
+ ~DWARFDIECollection()
+ {
+ }
+
+ void
+ Dump(lldb_private::Stream *s, const char* title) const;
+
+ const DWARFDebugInfoEntry*
+ GetDIEPtrAtIndex(uint32_t idx) const;
+
+ bool
+ Insert(const DWARFDebugInfoEntry *die);
+
+ size_t
+ Size() const;
+
+protected:
+ typedef std::vector<const DWARFDebugInfoEntry *> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_dies; // Ordered list of die offsets
+};
+
+
+#endif // SymbolFileDWARF_DWARFDIECollection_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
new file mode 100644
index 0000000..af6fc8e
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
@@ -0,0 +1,202 @@
+//===-- DWARFDebugAbbrev.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugAbbrev.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Clear()
+//----------------------------------------------------------------------
+void
+DWARFAbbreviationDeclarationSet::Clear()
+{
+ m_idx_offset = 0;
+ m_decls.clear();
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Extract()
+//----------------------------------------------------------------------
+bool
+DWARFAbbreviationDeclarationSet::Extract(const DataExtractor& data, uint32_t* offset_ptr)
+{
+ const uint32_t begin_offset = *offset_ptr;
+ m_offset = begin_offset;
+ Clear();
+ DWARFAbbreviationDeclaration abbrevDeclaration;
+ dw_uleb128_t prev_abbr_code = 0;
+ while (abbrevDeclaration.Extract(data, offset_ptr))
+ {
+ m_decls.push_back(abbrevDeclaration);
+ if (m_idx_offset == 0)
+ m_idx_offset = abbrevDeclaration.Code();
+ else
+ {
+ if (prev_abbr_code + 1 != abbrevDeclaration.Code())
+ m_idx_offset = UINT_MAX; // Out of order indexes, we can't do O(1) lookups...
+ }
+ prev_abbr_code = abbrevDeclaration.Code();
+ }
+ return begin_offset != *offset_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Dump()
+//----------------------------------------------------------------------
+void
+DWARFAbbreviationDeclarationSet::Dump(Stream *s) const
+{
+ std::for_each (m_decls.begin(), m_decls.end(), bind2nd(std::mem_fun_ref(&DWARFAbbreviationDeclaration::Dump),s));
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration()
+//----------------------------------------------------------------------
+const DWARFAbbreviationDeclaration*
+DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const
+{
+ if (m_idx_offset == UINT_MAX)
+ {
+ DWARFAbbreviationDeclarationCollConstIter pos;
+ DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
+ for (pos = m_decls.begin(); pos != end; ++pos)
+ {
+ if (pos->Code() == abbrCode)
+ return &(*pos);
+ }
+ }
+ else
+ {
+ uint32_t idx = abbrCode - m_idx_offset;
+ if (idx < m_decls.size())
+ return &m_decls[idx];
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential()
+//
+// Append an abbreviation declaration with a sequential code for O(n)
+// lookups. Handy when creating an DWARFAbbreviationDeclarationSet.
+//----------------------------------------------------------------------
+dw_uleb128_t
+DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl)
+{
+ // Get the next abbreviation code based on our current array size
+ dw_uleb128_t code = m_decls.size()+1;
+
+ // Push the new declaration on the back
+ m_decls.push_back(abbrevDecl);
+
+ // Update the code for this new declaration
+ m_decls.back().SetCode(code);
+
+ return code; // return the new abbreviation code!
+}
+
+
+//----------------------------------------------------------------------
+// Encode
+//
+// Encode the abbreviation table onto the end of the buffer provided
+// into a byte represenation as would be found in a ".debug_abbrev"
+// debug information section.
+//----------------------------------------------------------------------
+//void
+//DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf) const
+//{
+// DWARFAbbreviationDeclarationCollConstIter pos;
+// DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
+// for (pos = m_decls.begin(); pos != end; ++pos)
+// pos->Append(debug_abbrev_buf);
+// debug_abbrev_buf.Append8(0);
+//}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev constructor
+//----------------------------------------------------------------------
+DWARFDebugAbbrev::DWARFDebugAbbrev() :
+ m_abbrevCollMap(),
+ m_prev_abbr_offset_pos(m_abbrevCollMap.end())
+{
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::Parse()
+//----------------------------------------------------------------------
+void
+DWARFDebugAbbrev::Parse(const DataExtractor& data)
+{
+ uint32_t offset = 0;
+
+ while (data.ValidOffset(offset))
+ {
+ uint32_t initial_cu_offset = offset;
+ DWARFAbbreviationDeclarationSet abbrevDeclSet;
+
+ if (abbrevDeclSet.Extract(data, &offset))
+ m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet;
+ else
+ break;
+ }
+ m_prev_abbr_offset_pos = m_abbrevCollMap.end();
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::Dump()
+//----------------------------------------------------------------------
+void
+DWARFDebugAbbrev::Dump(Stream *s) const
+{
+ if (m_abbrevCollMap.empty())
+ {
+ s->PutCString("< EMPTY >\n");
+ return;
+ }
+
+ DWARFAbbreviationDeclarationCollMapConstIter pos;
+ for (pos = m_abbrevCollMap.begin(); pos != m_abbrevCollMap.end(); ++pos)
+ {
+ s->Printf("Abbrev table for offset: 0x%8.8x\n", pos->first);
+ pos->second.Dump(s);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::GetAbbreviationDeclarationSet()
+//----------------------------------------------------------------------
+const DWARFAbbreviationDeclarationSet*
+DWARFDebugAbbrev::GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const
+{
+ DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end();
+ DWARFAbbreviationDeclarationCollMapConstIter pos;
+ if (m_prev_abbr_offset_pos != end && m_prev_abbr_offset_pos->first == cu_abbr_offset)
+ return &(m_prev_abbr_offset_pos->second);
+ else
+ {
+ pos = m_abbrevCollMap.find(cu_abbr_offset);
+ m_prev_abbr_offset_pos = pos;
+ }
+
+ if (pos != m_abbrevCollMap.end());
+ return &(pos->second);
+ return NULL;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
new file mode 100644
index 0000000..3185d98
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
@@ -0,0 +1,74 @@
+//===-- DWARFDebugAbbrev.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_DWARFDebugAbbrev_h_
+#define SymbolFileDWARF_DWARFDebugAbbrev_h_
+
+#include <list>
+#include <map>
+
+#include "lldb/lldb-private.h"
+
+#include "DWARFDefines.h"
+#include "DWARFAbbreviationDeclaration.h"
+
+typedef std::vector<DWARFAbbreviationDeclaration> DWARFAbbreviationDeclarationColl;
+typedef DWARFAbbreviationDeclarationColl::iterator DWARFAbbreviationDeclarationCollIter;
+typedef DWARFAbbreviationDeclarationColl::const_iterator DWARFAbbreviationDeclarationCollConstIter;
+
+
+class DWARFAbbreviationDeclarationSet
+{
+public:
+ DWARFAbbreviationDeclarationSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_idx_offset(0),
+ m_decls()
+ {
+ }
+
+ DWARFAbbreviationDeclarationSet(dw_offset_t offset, uint32_t idx_offset) :
+ m_offset(offset),
+ m_idx_offset(idx_offset),
+ m_decls()
+ {
+ }
+
+ void Clear();
+ dw_offset_t GetOffset() const { return m_offset; }
+ void Dump(lldb_private::Stream *s) const;
+ bool Extract(const lldb_private::DataExtractor& data, uint32_t* offset_ptr);
+ //void Encode(BinaryStreamBuf& debug_abbrev_buf) const;
+ dw_uleb128_t AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl);
+
+ const DWARFAbbreviationDeclaration* GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const;
+private:
+ dw_offset_t m_offset;
+ uint32_t m_idx_offset;
+ std::vector<DWARFAbbreviationDeclaration> m_decls;
+};
+
+typedef std::map<dw_offset_t, DWARFAbbreviationDeclarationSet> DWARFAbbreviationDeclarationCollMap;
+typedef DWARFAbbreviationDeclarationCollMap::iterator DWARFAbbreviationDeclarationCollMapIter;
+typedef DWARFAbbreviationDeclarationCollMap::const_iterator DWARFAbbreviationDeclarationCollMapConstIter;
+
+
+class DWARFDebugAbbrev
+{
+public:
+ DWARFDebugAbbrev();
+ const DWARFAbbreviationDeclarationSet* GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const;
+ void Dump(lldb_private::Stream *s) const;
+ void Parse(const lldb_private::DataExtractor& data);
+protected:
+ DWARFAbbreviationDeclarationCollMap m_abbrevCollMap;
+ mutable DWARFAbbreviationDeclarationCollMapConstIter m_prev_abbr_offset_pos;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugAbbrev_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 0000000..57ef6ba
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
@@ -0,0 +1,274 @@
+//===-- DWARFDebugArangeSet.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugArangeSet.h"
+
+#include <assert.h>
+#include "lldb/Core/Stream.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+
+DWARFDebugArangeSet::DWARFDebugArangeSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_header(),
+ m_arange_descriptors()
+{
+ m_header.length = 0;
+ m_header.version = 0;
+ m_header.cu_offset = 0;
+ m_header.addr_size = 0;
+ m_header.seg_size = 0;
+}
+
+void
+DWARFDebugArangeSet::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_header.length = 0;
+ m_header.version = 0;
+ m_header.cu_offset = 0;
+ m_header.addr_size = 0;
+ m_header.seg_size = 0;
+ m_arange_descriptors.clear();
+}
+
+void
+DWARFDebugArangeSet::SetHeader
+(
+ uint16_t version,
+ uint32_t cu_offset,
+ uint8_t addr_size,
+ uint8_t seg_size
+)
+{
+ m_header.version = version;
+ m_header.cu_offset = cu_offset;
+ m_header.addr_size = addr_size;
+ m_header.seg_size = seg_size;
+}
+
+void
+DWARFDebugArangeSet::Compact()
+{
+ if (m_arange_descriptors.empty())
+ return;
+
+ // Iterate through all arange descriptors and combine any ranges that
+ // overlap or have matching boundaries. The m_arange_descriptors are assumed
+ // to be in ascending order after being built by adding descriptors
+ // using the AddDescriptor method.
+ uint32_t i = 0;
+ while (i + 1 < m_arange_descriptors.size())
+ {
+ if (m_arange_descriptors[i].end_address() >= m_arange_descriptors[i+1].address)
+ {
+ // The current range ends at or exceeds the start of the next address range.
+ // Compute the max end address between the two and use that to make the new
+ // length.
+ const dw_addr_t max_end_addr = std::max(m_arange_descriptors[i].end_address(), m_arange_descriptors[i+1].end_address());
+ m_arange_descriptors[i].length = max_end_addr - m_arange_descriptors[i].address;
+ // Now remove the next entry as it was just combined with the previous one.
+ m_arange_descriptors.erase(m_arange_descriptors.begin()+i+1);
+ }
+ else
+ {
+ // Discontiguous address range, just proceed to the next one.
+ ++i;
+ }
+ }
+}
+//----------------------------------------------------------------------
+// Compare function DWARFDebugArangeSet::Descriptor structures
+//----------------------------------------------------------------------
+static bool DescriptorLessThan (const DWARFDebugArangeSet::Descriptor& range1, const DWARFDebugArangeSet::Descriptor& range2)
+{
+ return range1.address < range2.address;
+}
+
+//----------------------------------------------------------------------
+// Add a range descriptor and keep things sorted so we can easily
+// compact the ranges before being saved or used.
+//----------------------------------------------------------------------
+void
+DWARFDebugArangeSet::AddDescriptor(const DWARFDebugArangeSet::Descriptor& range)
+{
+ if (m_arange_descriptors.empty())
+ {
+ m_arange_descriptors.push_back(range);
+ return;
+ }
+
+ DescriptorIter end = m_arange_descriptors.end();
+ DescriptorIter pos = lower_bound(m_arange_descriptors.begin(), end, range, DescriptorLessThan);
+ const dw_addr_t range_end_addr = range.end_address();
+ if (pos != end)
+ {
+ const dw_addr_t found_end_addr = pos->end_address();
+ if (range.address < pos->address)
+ {
+ if (range_end_addr < pos->address)
+ {
+ // Non-contiguous entries, add this one before the found entry
+ m_arange_descriptors.insert(pos, range);
+ }
+ else if (range_end_addr == pos->address)
+ {
+ // The top end of 'range' is the lower end of the entry
+ // pointed to by 'pos'. We can combine range with the
+ // entry we found by setting the starting address and
+ // increasing the length since they don't overlap.
+ pos->address = range.address;
+ pos->length += range.length;
+ }
+ else
+ {
+ // We can combine these two and make sure the largest end
+ // address is used to make end address.
+ pos->address = range.address;
+ pos->length = std::max(found_end_addr, range_end_addr) - pos->address;
+ }
+ }
+ else if (range.address == pos->address)
+ {
+ pos->length = std::max(pos->length, range.length);
+ }
+ }
+ else
+ {
+ // NOTE: 'pos' points to entry past the end which is ok for insert,
+ // don't use otherwise!!!
+ const dw_addr_t max_addr = m_arange_descriptors.back().end_address();
+ if (max_addr < range.address)
+ {
+ // Non-contiguous entries, add this one before the found entry
+ m_arange_descriptors.insert(pos, range);
+ }
+ else if (max_addr == range.address)
+ {
+ m_arange_descriptors.back().length += range.length;
+ }
+ else
+ {
+ m_arange_descriptors.back().length = std::max(max_addr, range_end_addr) - m_arange_descriptors.back().address;
+ }
+ }
+}
+
+bool
+DWARFDebugArangeSet::Extract(const DataExtractor &data, uint32_t* offset_ptr)
+{
+ if (data.ValidOffset(*offset_ptr))
+ {
+ m_arange_descriptors.clear();
+ m_offset = *offset_ptr;
+
+ // 7.20 Address Range Table
+ //
+ // Each set of entries in the table of address ranges contained in
+ // the .debug_aranges section begins with a header consisting of: a
+ // 4-byte length containing the length of the set of entries for this
+ // compilation unit, not including the length field itself; a 2-byte
+ // version identifier containing the value 2 for DWARF Version 2; a
+ // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
+ // containing the size in bytes of an address (or the offset portion of
+ // an address for segmented addressing) on the target system; and a
+ // 1-byte unsigned integer containing the size in bytes of a segment
+ // descriptor on the target system. This header is followed by a series
+ // of tuples. Each tuple consists of an address and a length, each in
+ // the size appropriate for an address on the target architecture.
+ m_header.length = data.GetU32(offset_ptr);
+ m_header.version = data.GetU16(offset_ptr);
+ m_header.cu_offset = data.GetU32(offset_ptr);
+ m_header.addr_size = data.GetU8(offset_ptr);
+ m_header.seg_size = data.GetU8(offset_ptr);
+
+
+ // The first tuple following the header in each set begins at an offset
+ // that is a multiple of the size of a single tuple (that is, twice the
+ // size of an address). The header is padded, if necessary, to the
+ // appropriate boundary.
+ const uint32_t header_size = *offset_ptr - m_offset;
+ const uint32_t tuple_size = m_header.addr_size << 1;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ *offset_ptr = m_offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length));
+ assert(sizeof(arangeDescriptor.address) >= m_header.addr_size);
+
+ while (data.ValidOffset(*offset_ptr))
+ {
+ arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
+ arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
+
+ // Each set of tuples is terminated by a 0 for the address and 0
+ // for the length.
+ if (arangeDescriptor.address || arangeDescriptor.length)
+ m_arange_descriptors.push_back(arangeDescriptor);
+ else
+ break; // We are done if we get a zero address and length
+ }
+
+ return !m_arange_descriptors.empty();
+ }
+ return false;
+}
+
+
+dw_offset_t
+DWARFDebugArangeSet::GetOffsetOfNextEntry() const
+{
+ return m_offset + m_header.length + 4;
+}
+
+
+void
+DWARFDebugArangeSet::Dump(Stream *s) const
+{
+ s->Printf("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
+ m_header.length ,m_header.version, m_header.cu_offset, m_header.addr_size, m_header.seg_size);
+
+ const uint32_t hex_width = m_header.addr_size * 2;
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_arange_descriptors.end();
+ for (pos = m_arange_descriptors.begin(); pos != end; ++pos)
+ s->Printf("[0x%*.*llx - 0x%*.*llx)\n",
+ hex_width, hex_width, pos->address,
+ hex_width, hex_width, pos->end_address());
+}
+
+
+class DescriptorContainsAddress
+{
+public:
+ DescriptorContainsAddress (dw_addr_t address) : m_address(address) {}
+ bool operator() (const DWARFDebugArangeSet::Descriptor& desc) const
+ {
+ return (m_address >= desc.address) && (m_address < (desc.address + desc.length));
+ }
+ private:
+ const dw_addr_t m_address;
+};
+
+dw_offset_t
+DWARFDebugArangeSet::FindAddress(dw_addr_t address) const
+{
+ DescriptorConstIter end = m_arange_descriptors.end();
+ DescriptorConstIter pos = std::find_if( m_arange_descriptors.begin(), end, // Range
+ DescriptorContainsAddress(address));// Predicate
+ if (pos != end)
+ return m_header.cu_offset;
+
+ return DW_INVALID_OFFSET;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
new file mode 100644
index 0000000..fc1e391
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
@@ -0,0 +1,70 @@
+//===-- DWARFDebugArangeSet.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_DWARFDebugArangeSet_h_
+#define SymbolFileDWARF_DWARFDebugArangeSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class SymbolFileDWARF;
+
+class DWARFDebugArangeSet
+{
+public:
+ typedef struct HeaderTag
+ {
+ uint32_t length; // The total length of the entries for that set, not including the length field itself.
+ uint16_t version; // The DWARF version number
+ uint32_t cu_offset; // The offset from the beginning of the .debug_info section of the compilation unit entry referenced by the table.
+ uint8_t addr_size; // The size in bytes of an address on the target architecture. For segmented addressing, this is the size of the offset portion of the address
+ uint8_t seg_size; // The size in bytes of a segment descriptor on the target architecture. If the target system uses a flat address space, this value is 0.
+ } Header;
+
+ typedef struct DescriptorTag
+ {
+ dw_addr_t address;
+ dw_addr_t length;
+ dw_addr_t end_address() const { return address + length; }
+ } Descriptor;
+
+
+ DWARFDebugArangeSet();
+ void Clear();
+ void SetOffset(uint32_t offset) { m_offset = offset; }
+ void SetHeader(uint16_t version, uint32_t cu_offset, uint8_t addr_size, uint8_t seg_size);
+ void AddDescriptor(const DWARFDebugArangeSet::Descriptor& range);
+ void Compact();
+ bool Extract(const lldb_private::DataExtractor &data, uint32_t* offset_ptr);
+ void Dump(lldb_private::Stream *s) const;
+ dw_offset_t GetCompileUnitDIEOffset() const { return m_header.cu_offset; }
+ dw_offset_t GetOffsetOfNextEntry() const;
+ dw_offset_t FindAddress(dw_addr_t address) const;
+ uint32_t NumDescriptors() const { return m_arange_descriptors.size(); }
+ const Header& GetHeader() const { return m_header; }
+ const Descriptor* GetDescriptor(uint32_t i) const
+ {
+ if (i < m_arange_descriptors.size())
+ return &m_arange_descriptors[i];
+ return NULL;
+ }
+
+
+protected:
+ typedef std::vector<Descriptor> DescriptorColl;
+ typedef DescriptorColl::iterator DescriptorIter;
+ typedef DescriptorColl::const_iterator DescriptorConstIter;
+
+
+ uint32_t m_offset;
+ Header m_header;
+ DescriptorColl m_arange_descriptors;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugArangeSet_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 0000000..a3213e0
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,343 @@
+//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugAranges.h"
+
+#include <assert.h>
+
+#include <algorithm>
+
+#include "lldb/Core/Stream.h"
+
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugAranges::DWARFDebugAranges() :
+ m_aranges()
+{
+}
+
+
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool RangeLessThan (const DWARFDebugAranges::Range& range1, const DWARFDebugAranges::Range& range2)
+{
+// printf("RangeLessThan -- 0x%8.8x < 0x%8.8x ? %d\n", range1.lo_pc, range1.lo_pc, range1.lo_pc < range2.lo_pc);
+ return range1.lo_pc < range2.lo_pc;
+}
+
+//----------------------------------------------------------------------
+// CountArangeDescriptors
+//----------------------------------------------------------------------
+class CountArangeDescriptors
+{
+public:
+ CountArangeDescriptors (uint32_t& count_ref) : count(count_ref)
+ {
+// printf("constructor CountArangeDescriptors()\n");
+ }
+ void operator() (const DWARFDebugArangeSet& set)
+ {
+ count += set.NumDescriptors();
+ }
+ uint32_t& count;
+};
+
+//----------------------------------------------------------------------
+// AddArangeDescriptors
+//----------------------------------------------------------------------
+class AddArangeDescriptors
+{
+public:
+ AddArangeDescriptors (DWARFDebugAranges::RangeColl& ranges) : range_collection(ranges) {}
+ void operator() (const DWARFDebugArangeSet& set)
+ {
+ const DWARFDebugArangeSet::Descriptor* arange_desc_ptr;
+ DWARFDebugAranges::Range range;
+ range.offset = set.GetCompileUnitDIEOffset();
+
+ for (uint32_t i=0; arange_desc_ptr = set.GetDescriptor(i); ++i)
+ {
+ range.lo_pc = arange_desc_ptr->address;
+ range.hi_pc = arange_desc_ptr->address + arange_desc_ptr->length;
+
+ // Insert each item in increasing address order so binary searching
+ // can later be done!
+ DWARFDebugAranges::RangeColl::iterator insert_pos = lower_bound(range_collection.begin(), range_collection.end(), range, RangeLessThan);
+ range_collection.insert(insert_pos, range);
+ }
+ }
+ DWARFDebugAranges::RangeColl& range_collection;
+};
+
+//----------------------------------------------------------------------
+// PrintRange
+//----------------------------------------------------------------------
+static void PrintRange(const DWARFDebugAranges::Range& range)
+{
+ // Cast the address values in case the address type is compiled as 32 bit
+ printf("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.offset, (uint64_t)range.lo_pc, (uint64_t)range.hi_pc);
+}
+
+//----------------------------------------------------------------------
+// Extract
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data)
+{
+ if (debug_aranges_data.ValidOffset(0))
+ {
+ uint32_t offset = 0;
+
+ typedef std::vector<DWARFDebugArangeSet> SetCollection;
+ typedef SetCollection::const_iterator SetCollectionIter;
+ SetCollection sets;
+
+ DWARFDebugArangeSet set;
+ Range range;
+ while (set.Extract(debug_aranges_data, &offset))
+ sets.push_back(set);
+
+ uint32_t count = 0;
+
+ for_each(sets.begin(), sets.end(), CountArangeDescriptors(count));
+
+ if (count > 0)
+ {
+ m_aranges.reserve(count);
+ AddArangeDescriptors range_adder(m_aranges);
+ for_each(sets.begin(), sets.end(), range_adder);
+ }
+
+ // puts("\n\nDWARFDebugAranges list is:\n");
+ // for_each(m_aranges.begin(), m_aranges.end(), PrintRange);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Generate
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
+{
+ Clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ if (cu)
+ cu->DIE()->BuildAddressRangeTable(dwarf2Data, cu, this);
+ }
+ }
+ return !IsEmpty();
+}
+
+
+void
+DWARFDebugAranges::Print() const
+{
+ puts("\n\nDWARFDebugAranges address range list is:\n");
+ for_each(m_aranges.begin(), m_aranges.end(), PrintRange);
+}
+
+
+void
+DWARFDebugAranges::Range::Dump(Stream *s) const
+{
+ s->Printf("{0x%8.8x}: [0x%8.8llx - 0x%8.8llx)\n", offset, lo_pc, hi_pc);
+}
+
+//----------------------------------------------------------------------
+// Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugAranges::Dump(SymbolFileDWARF* dwarf2Data, Stream *s)
+{
+ const DataExtractor &debug_aranges_data = dwarf2Data->get_debug_aranges_data();
+ if (debug_aranges_data.ValidOffset(0))
+ {
+ uint32_t offset = 0;
+
+ DWARFDebugArangeSet set;
+ while (set.Extract(debug_aranges_data, &offset))
+ set.Dump(s);
+ }
+ else
+ s->PutCString("< EMPTY >\n");
+}
+
+
+//----------------------------------------------------------------------
+// AppendDebugRanges
+//----------------------------------------------------------------------
+//void
+//DWARFDebugAranges::AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const
+//{
+// if (!m_aranges.empty())
+// {
+// RangeCollIterator end = m_aranges.end();
+// RangeCollIterator pos;
+// RangeCollIterator lo_pos = end;
+// for (pos = m_aranges.begin(); pos != end; ++pos)
+// {
+// if (lo_pos == end)
+// lo_pos = pos;
+//
+// RangeCollIterator next = pos + 1;
+// if (next != end)
+// {
+// // Check to see if we can combine two consecutive ranges?
+// if (pos->hi_pc == next->lo_pc)
+// continue; // We can combine them!
+// }
+//
+// if (cu_base_addr == 0 || cu_base_addr == DW_INVALID_ADDRESS)
+// {
+// debug_ranges.AppendMax64(lo_pos->lo_pc, addr_size);
+// debug_ranges.AppendMax64(pos->hi_pc, addr_size);
+// }
+// else
+// {
+// assert(lo_pos->lo_pc >= cu_base_addr);
+// assert(pos->hi_pc >= cu_base_addr);
+// debug_ranges.AppendMax64(lo_pos->lo_pc - cu_base_addr, addr_size);
+// debug_ranges.AppendMax64(pos->hi_pc - cu_base_addr, addr_size);
+// }
+//
+// // Reset the low part of the next address range
+// lo_pos = end;
+// }
+// }
+// // Terminate the .debug_ranges with two zero addresses
+// debug_ranges.AppendMax64(0, addr_size);
+// debug_ranges.AppendMax64(0, addr_size);
+//
+//}
+//
+//----------------------------------------------------------------------
+// ArangeSetContainsAddress
+//----------------------------------------------------------------------
+class ArangeSetContainsAddress
+{
+public:
+ ArangeSetContainsAddress (dw_addr_t the_address) : address(the_address), offset(DW_INVALID_OFFSET) {}
+ bool operator() (const DWARFDebugArangeSet& set)
+ {
+ offset = set.FindAddress(address);
+ return (offset != DW_INVALID_OFFSET);
+ }
+ const dw_addr_t address;
+ dw_offset_t offset;
+};
+
+
+//----------------------------------------------------------------------
+// InsertRange
+//----------------------------------------------------------------------
+void
+DWARFDebugAranges::InsertRange(dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
+{
+ // Insert each item in increasing address order so binary searching
+ // can later be done!
+ DWARFDebugAranges::Range range(low_pc, high_pc, offset);
+ InsertRange(range);
+}
+
+//----------------------------------------------------------------------
+// InsertRange
+//----------------------------------------------------------------------
+void
+DWARFDebugAranges::InsertRange(const DWARFDebugAranges::Range& range)
+{
+ // Insert each item in increasing address order so binary searching
+ // can later be done!
+ RangeColl::iterator insert_pos = lower_bound(m_aranges.begin(), m_aranges.end(), range, RangeLessThan);
+ m_aranges.insert(insert_pos, range);
+}
+
+
+//----------------------------------------------------------------------
+// FindAddress
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugAranges::FindAddress(dw_addr_t address) const
+{
+ if ( !m_aranges.empty() )
+ {
+ DWARFDebugAranges::Range range(address);
+ DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin();
+ DWARFDebugAranges::RangeCollIterator end = m_aranges.end();
+ DWARFDebugAranges::RangeCollIterator pos = lower_bound(begin, end, range, RangeLessThan);
+
+ if ((pos != end) && (pos->lo_pc <= address && address < pos->hi_pc))
+ {
+ // printf("FindAddress(1) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset);
+ return pos->offset;
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if ((pos->lo_pc <= address) && (address < pos->hi_pc))
+ {
+ // printf("FindAddress(2) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset);
+ return (*pos).offset;
+ }
+ }
+ }
+ return DW_INVALID_OFFSET;
+}
+
+//----------------------------------------------------------------------
+// AllRangesAreContiguous
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const
+{
+ if (m_aranges.empty())
+ return false;
+
+ DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin();
+ DWARFDebugAranges::RangeCollIterator end = m_aranges.end();
+ DWARFDebugAranges::RangeCollIterator pos;
+ dw_addr_t next_addr = 0;
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if ((pos != begin) && (pos->lo_pc != next_addr))
+ return false;
+ next_addr = pos->hi_pc;
+ }
+ lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid
+ hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid
+ return true;
+}
+
+bool
+DWARFDebugAranges::GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const
+{
+ if (m_aranges.empty())
+ return false;
+
+ lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid
+ hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid
+ return true;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
new file mode 100644
index 0000000..f3db949
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
@@ -0,0 +1,98 @@
+//===-- DWARFDebugAranges.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_DWARFDebugAranges_h_
+#define SymbolFileDWARF_DWARFDebugAranges_h_
+
+#include "DWARFDebugArangeSet.h"
+#include <list>
+
+class SymbolFileDWARF;
+
+class DWARFDebugAranges
+{
+public:
+ struct Range
+ {
+ Range(
+ dw_addr_t _lo_pc = DW_INVALID_ADDRESS,
+ dw_addr_t _hi_pc = DW_INVALID_ADDRESS,
+ dw_offset_t _offset = DW_INVALID_OFFSET) :
+ lo_pc(_lo_pc),
+ hi_pc(_hi_pc),
+ offset(_offset)
+ {
+ }
+
+ void Clear()
+ {
+ lo_pc = hi_pc = DW_INVALID_ADDRESS;
+ offset = DW_INVALID_OFFSET;
+ }
+
+ bool ValidRange() const
+ {
+ return hi_pc > lo_pc;
+ }
+
+ bool Contains(const Range& range) const
+ {
+ return lo_pc <= range.lo_pc && range.hi_pc <= hi_pc;
+ }
+
+ void Dump(lldb_private::Stream *s) const;
+ dw_addr_t lo_pc; // Start of address range
+ dw_addr_t hi_pc; // End of address range (not including this address)
+ dw_offset_t offset; // Offset of the compile unit or die
+ };
+
+ DWARFDebugAranges();
+
+ void Clear() { m_aranges.clear(); }
+ bool AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const;
+ bool GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const;
+ bool Extract(const lldb_private::DataExtractor &debug_aranges_data);
+ bool Generate(SymbolFileDWARF* dwarf2Data);
+ void InsertRange(dw_offset_t cu_offset, dw_addr_t low_pc, dw_addr_t high_pc);
+ void InsertRange(const DWARFDebugAranges::Range& range);
+ const Range* RangeAtIndex(uint32_t idx) const
+ {
+ if (idx < m_aranges.size())
+ return &m_aranges[idx];
+ return NULL;
+ }
+ void Print() const;
+ dw_offset_t FindAddress(dw_addr_t address) const;
+ bool IsEmpty() const { return m_aranges.empty(); }
+ void Dump(lldb_private::Stream *s);
+ uint32_t NumRanges() const
+ {
+ return m_aranges.size();
+ }
+
+ dw_offset_t OffsetAtIndex(uint32_t idx) const
+ {
+ if (idx < m_aranges.size())
+ return m_aranges[idx].offset;
+ return DW_INVALID_OFFSET;
+ }
+// void AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const;
+
+ static void Dump(SymbolFileDWARF* dwarf2Data, lldb_private::Stream *s);
+
+ typedef std::vector<Range> RangeColl;
+ typedef RangeColl::const_iterator RangeCollIterator;
+
+protected:
+
+ RangeColl m_aranges;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugAranges_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
new file mode 100644
index 0000000..fcb0ccf
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -0,0 +1,1206 @@
+//===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+#include <algorithm>
+#include <set>
+
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+
+#include "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFFormValue.h"
+
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugInfo::DWARFDebugInfo() :
+ m_dwarf2Data(NULL),
+ m_compile_units()
+{
+}
+
+//----------------------------------------------------------------------
+// SetDwarfData
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data)
+{
+ m_dwarf2Data = dwarf2Data;
+ m_compile_units.clear();
+}
+
+//----------------------------------------------------------------------
+// BuildDIEAddressRangeTable
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::BuildFunctionAddressRangeTable(DWARFDebugAranges* debug_aranges)
+{
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ uint32_t idx;
+ for (idx = 0; idx < num_compile_units; ++idx)
+ {
+ DWARFCompileUnit* cu = GetCompileUnitAtIndex (idx);
+ if (cu)
+ {
+ cu->DIE()->BuildFunctionAddressRangeTable(m_dwarf2Data, cu, debug_aranges);
+ }
+ }
+ return !debug_aranges->IsEmpty();
+}
+
+//----------------------------------------------------------------------
+// LookupAddress
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::LookupAddress
+(
+ const dw_addr_t address,
+ const dw_offset_t hint_die_offset,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die
+)
+{
+
+ if (hint_die_offset != DW_INVALID_OFFSET)
+ cu_sp = GetCompileUnit(hint_die_offset);
+ else
+ {
+ // Get a non const version of the address ranges
+ DWARFDebugAranges* debug_aranges = ((SymbolFileDWARF*)m_dwarf2Data)->DebugAranges();
+
+ if (debug_aranges != NULL)
+ {
+ // If we have an empty address ranges section, lets build a sorted
+ // table ourselves by going through all of the debug information so we
+ // can do quick subsequent searches.
+
+ if (debug_aranges->IsEmpty())
+ {
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ uint32_t idx;
+ for (idx = 0; idx < num_compile_units; ++idx)
+ {
+ DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx);
+ if (cu)
+ cu->DIE()->BuildAddressRangeTable(m_dwarf2Data, cu, debug_aranges);
+ }
+ }
+ cu_sp = GetCompileUnit(debug_aranges->FindAddress(address));
+ }
+ }
+
+ if (cu_sp.get())
+ {
+ if (cu_sp->LookupAddress(address, function_die, block_die))
+ return true;
+ cu_sp.reset();
+ }
+ else
+ {
+ // The hint_die_offset may have been a pointer to the actual item that
+ // we are looking for
+ DWARFDebugInfoEntry* die_ptr = GetDIEPtr(hint_die_offset, &cu_sp);
+ if (die_ptr)
+ {
+ if (cu_sp.get())
+ {
+ if (function_die || block_die)
+ return die_ptr->LookupAddress(address, m_dwarf2Data, cu_sp.get(), function_die, block_die);
+
+ // We only wanted the compile unit that contained this address
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+void
+DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded()
+{
+ if (m_compile_units.empty())
+ {
+ if (m_dwarf2Data != NULL)
+ {
+ uint32_t offset = 0;
+ const DataExtractor &debug_info_data = m_dwarf2Data->get_debug_info_data();
+ while (debug_info_data.ValidOffset(offset))
+ {
+ DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data));
+ // Out of memory?
+ if (cu_sp.get() == NULL)
+ break;
+
+ if (cu_sp->Extract(debug_info_data, &offset) == false)
+ break;
+
+ m_compile_units.push_back(cu_sp);
+
+ offset = cu_sp->GetNextCompileUnitOffset();
+ }
+ }
+ }
+}
+
+uint32_t
+DWARFDebugInfo::GetNumCompileUnits()
+{
+ ParseCompileUnitHeadersIfNeeded();
+ return m_compile_units.size();
+}
+
+DWARFCompileUnit*
+DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx)
+{
+ DWARFCompileUnit* cu = NULL;
+ if (idx < GetNumCompileUnits())
+ cu = m_compile_units[idx].get();
+ return cu;
+}
+
+static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b)
+{
+ return a->GetOffset() < b->GetOffset();
+}
+
+
+static int
+CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem)
+{
+ const dw_offset_t key_cu_offset = *(dw_offset_t*) key;
+ const dw_offset_t cu_offset = ((DWARFCompileUnitSP *)arrmem)->get()->GetOffset();
+ if (key_cu_offset < cu_offset)
+ return -1;
+ if (key_cu_offset > cu_offset)
+ return 1;
+ return 0;
+}
+
+DWARFCompileUnitSP
+DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr)
+{
+ DWARFCompileUnitSP cu_sp;
+ uint32_t cu_idx = DW_INVALID_INDEX;
+ if (cu_offset != DW_INVALID_OFFSET)
+ {
+ ParseCompileUnitHeadersIfNeeded();
+
+ DWARFCompileUnitSP* match = (DWARFCompileUnitSP*)bsearch(&cu_offset, &m_compile_units[0], m_compile_units.size(), sizeof(DWARFCompileUnitSP), CompareDWARFCompileUnitSPOffset);
+ if (match)
+ {
+ cu_sp = *match;
+ cu_idx = match - &m_compile_units[0];
+ }
+ }
+ if (idx_ptr)
+ *idx_ptr = cu_idx;
+ return cu_sp;
+}
+
+DWARFCompileUnitSP
+DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset)
+{
+ DWARFCompileUnitSP cu_sp;
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ParseCompileUnitHeadersIfNeeded();
+
+ CompileUnitColl::const_iterator end_pos = m_compile_units.end();
+ CompileUnitColl::const_iterator pos;
+
+ for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
+ {
+ dw_offset_t cu_start_offset = (*pos)->GetOffset();
+ dw_offset_t cu_end_offset = (*pos)->GetNextCompileUnitOffset();
+ if (cu_start_offset <= die_offset && die_offset < cu_end_offset)
+ {
+ cu_sp = *pos;
+ break;
+ }
+ }
+ }
+ return cu_sp;
+}
+
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
+{
+ return die1.GetOffset() < die2.GetOffset();
+}
+
+
+//----------------------------------------------------------------------
+// GetDIE()
+//
+// Get the DIE (Debug Information Entry) with the specified offset.
+//----------------------------------------------------------------------
+DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
+{
+ DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp_ptr)
+ *cu_sp_ptr = cu_sp;
+ if (cu_sp.get())
+ return cu_sp->GetDIEPtr(die_offset);
+ return NULL; // Not found in any compile units
+}
+
+const DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
+{
+ DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp_ptr)
+ *cu_sp_ptr = cu_sp;
+ if (cu_sp.get())
+ return cu_sp->GetDIEPtrContainingOffset(die_offset);
+
+ return NULL; // Not found in any compile units
+
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugInfo_ParseCallback
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets parses all compile units and DIE's into an internate
+// representation for further modification.
+//----------------------------------------------------------------------
+
+static dw_offset_t
+DWARFDebugInfo_ParseCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData;
+ DWARFCompileUnit* cu = cu_sp.get();
+ if (die)
+ {
+ cu->AddDIE(*die);
+ }
+ else if (cu)
+ {
+ debug_info->AddCompileUnit(cu_sp);
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// AddCompileUnit
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::AddCompileUnit(DWARFCompileUnitSP& cu)
+{
+ m_compile_units.push_back(cu);
+}
+
+/*
+void
+DWARFDebugInfo::AddDIE(DWARFDebugInfoEntry& die)
+{
+ m_die_array.push_back(die);
+}
+*/
+
+
+
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parses the .debug_info section and uses the .debug_abbrev section
+// and various other sections in the SymbolFileDWARF class and calls the
+// supplied callback function each time a compile unit header, or debug
+// information entry is successfully parsed. This function can be used
+// for different tasks such as parsing the file contents into a
+// structured data, dumping, verifying and much more.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Parse(SymbolFileDWARF* dwarf2Data, Callback callback, void* userData)
+{
+ if (dwarf2Data)
+ {
+ uint32_t offset = 0;
+ uint32_t depth = 0;
+ DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data));
+ if (cu.get() == NULL)
+ return;
+ DWARFDebugInfoEntry die;
+
+ while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset))
+ {
+ const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset();
+
+ depth = 0;
+ // Call the callback funtion with no DIE pointer for the compile unit
+ // and get the offset that we are to continue to parse from
+ offset = callback(dwarf2Data, cu, NULL, offset, depth, userData);
+
+ // Make sure we are within our compile unit
+ if (offset < next_cu_offset)
+ {
+ // We are in our compile unit, parse starting at the offset
+ // we were told to parse
+ bool done = false;
+ while (!done && die.Extract(dwarf2Data, cu.get(), &offset))
+ {
+ // Call the callback funtion with DIE pointer that falls within the compile unit
+ offset = callback(dwarf2Data, cu, &die, offset, depth, userData);
+
+ if (die.IsNULL())
+ {
+ if (depth)
+ --depth;
+ else
+ done = true; // We are done with this compile unit!
+ }
+ else if (die.HasChildren())
+ ++depth;
+ }
+ }
+
+ // Make sure the offset returned is valid, and if not stop parsing.
+ // Returning DW_INVALID_OFFSET from this callback is a good way to end
+ // all parsing
+ if (!dwarf2Data->get_debug_info_data().ValidOffset(offset))
+ break;
+
+ // See if during the callback anyone retained a copy of the compile
+ // unit other than ourselves and if so, let whomever did own the object
+ // and create a new one for our own use!
+ if (!cu.unique())
+ cu.reset(new DWARFCompileUnit(dwarf2Data));
+
+
+ // Make sure we start on a propper
+ offset = next_cu_offset;
+ }
+ }
+}
+
+/*
+typedef struct AddressRangeTag
+{
+ dw_addr_t lo_pc;
+ dw_addr_t hi_pc;
+ dw_offset_t die_offset;
+} AddressRange;
+*/
+struct DIERange
+{
+ DIERange() :
+ range(),
+ lo_die_offset(),
+ hi_die_offset()
+ {
+ }
+
+ DWARFDebugAranges::Range range;
+ dw_offset_t lo_die_offset;
+ dw_offset_t hi_die_offset;
+};
+
+typedef struct DwarfStat
+{
+ DwarfStat() : count(0), byte_size(0) {}
+ uint32_t count;
+ uint32_t byte_size;
+} DwarfStat;
+
+typedef map<dw_attr_t, DwarfStat> DwarfAttrStatMap;
+
+typedef struct DIEStat
+{
+ DIEStat() : count(0), byte_size(0), attr_stats() {}
+ uint32_t count;
+ uint32_t byte_size;
+ DwarfAttrStatMap attr_stats;
+} DIEStat;
+
+typedef map<dw_tag_t, DIEStat> DIEStatMap;
+struct VerifyInfo
+{
+ VerifyInfo(Stream* the_strm) :
+ strm(the_strm),
+ die_ranges(),
+ addr_range_errors(0),
+ sibling_errors(0),
+ die_stats()
+ {
+ }
+
+ Stream* strm;
+ vector<DIERange> die_ranges;
+ uint32_t addr_range_errors;
+ uint32_t sibling_errors;
+ DIEStatMap die_stats;
+
+ DISALLOW_COPY_AND_ASSIGN(VerifyInfo);
+
+};
+
+
+//----------------------------------------------------------------------
+// VerifyCallback
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets called each time a compile unit header or debug information
+// entry is successfully parsed.
+//
+// This function will verify the DWARF information is well formed by
+// making sure that any DW_TAG_compile_unit tags that have valid address
+// ranges (DW_AT_low_pc and DW_AT_high_pc) have no gaps in the address
+// ranges of it contained DW_TAG_subprogram tags. Also the sibling chain
+// and relationships are verified to make sure nothing gets hosed up
+// when dead stripping occurs.
+//----------------------------------------------------------------------
+
+static dw_offset_t
+VerifyCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ VerifyInfo* verifyInfo = (VerifyInfo*)userData;
+
+ const DWARFCompileUnit* cu = cu_sp.get();
+ Stream *s = verifyInfo->strm;
+ bool verbose = s->GetVerbose();
+ if (die)
+ {
+ // die->Dump(dwarf2Data, cu, f);
+ const DWARFAbbreviationDeclaration* abbrevDecl = die->GetAbbreviationDeclarationPtr();
+ // We have a DIE entry
+ if (abbrevDecl)
+ {
+ const dw_offset_t die_offset = die->GetOffset();
+ const dw_offset_t sibling = die->GetAttributeValueAsReference(dwarf2Data, cu, DW_AT_sibling, DW_INVALID_OFFSET);
+
+ if (sibling != DW_INVALID_OFFSET)
+ {
+ if (sibling <= next_offset)
+ {
+ if (verifyInfo->sibling_errors++ == 0)
+ s->Printf("ERROR\n");
+ s->Printf(" 0x%8.8x: sibling attribyte (0x%8.8x) in this die is not valid: it is less than this DIE or some of its contents.\n", die->GetOffset(), sibling);
+ }
+ else if (sibling > verifyInfo->die_ranges.back().hi_die_offset)
+ {
+ if (verifyInfo->sibling_errors++ == 0)
+ s->Printf("ERROR\n");
+ s->Printf(" 0x%8.8x: sibling attribute (0x%8.8x) in this DIE is not valid: it is greater than the end of the parent scope.\n", die->GetOffset(), sibling);
+ }
+ }
+
+ if ((die_offset < verifyInfo->die_ranges.back().lo_die_offset) || (die_offset >= verifyInfo->die_ranges.back().hi_die_offset))
+ {
+ if (verifyInfo->sibling_errors++ == 0)
+ s->Printf("ERROR\n");
+ s->Printf(" 0x%8.8x: DIE offset is not within the parent DIE range {0x%8.8x}: (0x%8.8x - 0x%8.8x)\n",
+ die->GetOffset(),
+ verifyInfo->die_ranges.back().range.offset,
+ verifyInfo->die_ranges.back().lo_die_offset,
+ verifyInfo->die_ranges.back().hi_die_offset);
+
+ }
+
+ dw_tag_t tag = abbrevDecl->Tag();
+
+ // Keep some stats on this DWARF file
+ verifyInfo->die_stats[tag].count++;
+ verifyInfo->die_stats[tag].byte_size += (next_offset - die->GetOffset());
+
+ if (verbose)
+ {
+ DIEStat& tag_stat = verifyInfo->die_stats[tag];
+
+ const DataExtractor& debug_info = dwarf2Data->get_debug_info_data();
+
+ dw_offset_t offset = die->GetOffset();
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info.Skip_LEB128(&offset);
+
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ dw_attr_t attr;
+ dw_form_t form;
+ for (uint32_t idx = 0; idx < numAttributes; ++idx)
+ {
+ dw_offset_t start_offset = offset;
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(idx, attr, form);
+ DWARFFormValue::SkipValue(form, debug_info, &offset, cu);
+
+ if (tag_stat.attr_stats.find(attr) == tag_stat.attr_stats.end())
+ {
+ tag_stat.attr_stats[attr].count = 0;
+ tag_stat.attr_stats[attr].byte_size = 0;
+ }
+
+ tag_stat.attr_stats[attr].count++;
+ tag_stat.attr_stats[attr].byte_size += offset - start_offset;
+ }
+ }
+
+ DWARFDebugAranges::Range range;
+ range.offset = die->GetOffset();
+
+ switch (tag)
+ {
+ case DW_TAG_compile_unit:
+ // Check for previous subroutines that were within a previous
+ //
+ // VerifyAddressRangesForCU(verifyInfo);
+ // Remember which compile unit we are dealing with so we can verify
+ // the address ranges within it (if any) are contiguous. The DWARF
+ // spec states that if a compile unit TAG has high and low PC
+ // attributes, there must be no gaps in the address ranges of it's
+ // contained subtroutines. If there are gaps, the high and low PC
+ // must not be in the DW_TAG_compile_unit's attributes. Errors like
+ // this can crop up when optimized code is dead stripped and the debug
+ // information isn't properly fixed up for output.
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (range.lo_pc != DW_INVALID_ADDRESS)
+ {
+ range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (s->GetVerbose())
+ {
+ s->Printf("\n CU ");
+ range.Dump(s);
+ }
+ }
+ else
+ {
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_entry_pc, DW_INVALID_ADDRESS);
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ // If the DW_TAG_compile_unit that contained this function had a
+ // valid address range, add all of the valid subroutine address
+ // ranges to a collection of addresses which will be sorted
+ // and verified right before the next DW_TAG_compile_unit is
+ // processed to make sure that there are no gaps in the address
+ // range.
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (range.lo_pc != DW_INVALID_ADDRESS)
+ {
+ range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (range.hi_pc != DW_INVALID_ADDRESS)
+ {
+ range.offset = die->GetOffset();
+ bool valid = range.ValidRange();
+ if (!valid || s->GetVerbose())
+ {
+ s->Printf("\n FUNC ");
+ range.Dump(s);
+ if (!valid)
+ {
+ ++verifyInfo->addr_range_errors;
+ s->Printf(" ERROR: Invalid address range for function.");
+ }
+ }
+
+ // Only add to our subroutine ranges if our compile unit has a valid address range
+ // if (valid && verifyInfo->die_ranges.size() >= 2 && verifyInfo->die_ranges[1].range.ValidRange())
+ // verifyInfo->subroutine_ranges.InsertRange(range);
+ }
+ }
+ break;
+
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ {
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (range.lo_pc != DW_INVALID_ADDRESS)
+ {
+ range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (range.hi_pc != DW_INVALID_ADDRESS)
+ {
+ range.offset = die->GetOffset();
+ bool valid = range.ValidRange();
+ if (!valid || s->GetVerbose())
+ {
+ s->Printf("\n BLCK ");
+ range.Dump(s);
+ if (!valid)
+ {
+ ++verifyInfo->addr_range_errors;
+ s->Printf(" ERROR: Invalid address range for block or inlined subroutine.");
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (range.ValidRange() && verifyInfo->die_ranges.back().range.ValidRange())
+ {
+ if (!verifyInfo->die_ranges.back().range.Contains(range))
+ {
+ ++verifyInfo->addr_range_errors;
+ s->Printf("\n ");
+ range.Dump(s);
+ s->Printf(" ERROR: Range is not in parent");
+ verifyInfo->die_ranges.back().range.Dump(s);
+ }
+ }
+
+ if (die->HasChildren())
+ {
+ // Keep tabs on the valid address ranges for the current item to make
+ // sure that it all fits (make sure the sibling offsets got fixed up
+ // correctly if any functions were dead stripped).
+ DIERange die_range;
+ die_range.range = range;
+ die_range.lo_die_offset = next_offset;
+ die_range.hi_die_offset = sibling;
+ if (die_range.hi_die_offset == DW_INVALID_OFFSET)
+ die_range.hi_die_offset = verifyInfo->die_ranges.back().hi_die_offset;
+ verifyInfo->die_ranges.push_back(die_range);
+ }
+ }
+ else
+ {
+ // NULL entry
+ verifyInfo->die_ranges.pop_back();
+ }
+ }
+ else
+ {
+ // cu->Dump(ostrm_ptr); // Dump the compile unit for the DIE
+ // We have a new comile unit header
+ verifyInfo->die_ranges.clear();
+ DIERange die_range;
+ die_range.range.offset = cu->GetOffset();
+ die_range.lo_die_offset = next_offset;
+ die_range.hi_die_offset = cu->GetNextCompileUnitOffset();
+ verifyInfo->die_ranges.push_back(die_range);
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+
+class CompareDIEStatSizes
+{
+public:
+ bool operator() (const DIEStatMap::const_iterator& pos1, const DIEStatMap::const_iterator& pos2) const
+ {
+ return pos1->second.byte_size <= pos2->second.byte_size;
+ }
+};
+
+class CompareAttrDIEStatSizes
+{
+public:
+ bool operator() (const DwarfAttrStatMap::const_iterator& pos1, const DwarfAttrStatMap::const_iterator& pos2) const
+ {
+ return pos1->second.byte_size <= pos2->second.byte_size;
+ }
+};
+
+//----------------------------------------------------------------------
+// Verify
+//
+// Verifies the DWARF information is valid.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Verify(Stream *s, SymbolFileDWARF* dwarf2Data)
+{
+ s->Printf("Verifying Compile Unit Header chain.....");
+ VerifyInfo verifyInfo(s);
+ verifyInfo.addr_range_errors = 0;
+ verifyInfo.sibling_errors = 0;
+
+ bool verbose = s->GetVerbose();
+
+ uint32_t offset = 0;
+ if (verbose)
+ s->EOL();
+// vector<dw_offset_t> valid_cu_offsets;
+ DWARFCompileUnit cu (dwarf2Data);
+ bool success = true;
+ while ( success && dwarf2Data->get_debug_info_data().ValidOffset(offset+cu.Size()) )
+ {
+ success = cu.Extract (dwarf2Data->get_debug_info_data(), &offset);
+ if (!success)
+ s->Printf("ERROR\n");
+ // else
+ // valid_cu_offsets.push_back(cu.GetOffset());
+
+ cu.Verify(verifyInfo.strm);
+ offset = cu.GetNextCompileUnitOffset();
+ }
+
+ if (success)
+ s->Printf("OK\n");
+
+ s->Printf("Verifying address ranges and siblings...");
+ if (verbose)
+ s->EOL();
+ DWARFDebugInfo::Parse(dwarf2Data, VerifyCallback, &verifyInfo);
+
+// VerifyAddressRangesForCU(&verifyInfo);
+
+ if (verifyInfo.addr_range_errors > 0)
+ s->Printf("\nERRORS - %u error(s) were found.\n", verifyInfo.addr_range_errors);
+ else
+ s->Printf("OK\n");
+
+ uint32_t total_category_sizes[kNumTagCategories] = {0};
+ uint32_t total_category_count[kNumTagCategories] = {0};
+ uint32_t total_die_count = 0;
+ uint32_t total_die_size = 0;
+
+ typedef set<DIEStatMap::const_iterator, CompareDIEStatSizes> DIEStatBySizeMap;
+
+ s->PutCString( "\n"
+ "DWARF Statistics\n"
+ "Count Size Size % Tag\n"
+ "-------- -------- -------- -------------------------------------------\n");
+ DIEStatBySizeMap statBySizeMap;
+ DIEStatMap::const_iterator pos;
+ DIEStatMap::const_iterator end_pos = verifyInfo.die_stats.end();
+ for (pos = verifyInfo.die_stats.begin(); pos != end_pos; ++pos)
+ {
+ const uint32_t die_count = pos->second.count;
+ const uint32_t die_size = pos->second.byte_size;
+
+ statBySizeMap.insert(pos);
+ total_die_count += die_count;
+ total_die_size += die_size;
+ DW_TAG_CategoryEnum category = get_tag_category(pos->first);
+ total_category_sizes[category] += die_size;
+ total_category_count[category] += die_count;
+ }
+
+ float total_die_size_float = total_die_size;
+
+ DIEStatBySizeMap::const_reverse_iterator size_pos;
+ DIEStatBySizeMap::const_reverse_iterator size_pos_end = statBySizeMap.rend();
+ float percentage;
+ for (size_pos = statBySizeMap.rbegin(); size_pos != size_pos_end; ++size_pos)
+ {
+ pos = *size_pos;
+
+ const DIEStat& tag_stat = pos->second;
+
+ const uint32_t die_count = tag_stat.count;
+ const uint32_t die_size = tag_stat.byte_size;
+ percentage = ((float)die_size/total_die_size_float)*100.0;
+ s->Printf("%7u %8u %2.2f%% %s\n", die_count, die_size, percentage, DW_TAG_value_to_name(pos->first));
+
+ const DwarfAttrStatMap& attr_stats = tag_stat.attr_stats;
+ if (!attr_stats.empty())
+ {
+ typedef set<DwarfAttrStatMap::const_iterator, CompareAttrDIEStatSizes> DwarfAttrStatBySizeMap;
+ DwarfAttrStatBySizeMap attrStatBySizeMap;
+ DwarfAttrStatMap::const_iterator attr_stat_pos;
+ DwarfAttrStatMap::const_iterator attr_stat_pos_end = attr_stats.end();
+ for (attr_stat_pos = attr_stats.begin(); attr_stat_pos != attr_stat_pos_end; ++attr_stat_pos)
+ {
+ attrStatBySizeMap.insert(attr_stat_pos);
+ }
+
+ DwarfAttrStatBySizeMap::const_reverse_iterator attr_size_pos;
+ DwarfAttrStatBySizeMap::const_reverse_iterator attr_size_pos_end = attrStatBySizeMap.rend();
+ for (attr_size_pos = attrStatBySizeMap.rbegin(); attr_size_pos != attr_size_pos_end; ++attr_size_pos)
+ {
+ attr_stat_pos = *attr_size_pos;
+ percentage = ((float)attr_stat_pos->second.byte_size/die_size)*100.0;
+ s->Printf("%7u %8u %2.2f%% %s\n", attr_stat_pos->second.count, attr_stat_pos->second.byte_size, percentage, DW_AT_value_to_name(attr_stat_pos->first));
+ }
+ s->EOL();
+ }
+ }
+
+ s->Printf("-------- -------- -------- -------------------------------------------\n");
+ s->Printf("%7u %8u 100.00% Total for all DIEs\n", total_die_count, total_die_size);
+
+ float total_category_percentages[kNumTagCategories] =
+ {
+ ((float)total_category_sizes[TagCategoryVariable]/total_die_size_float)*100.0,
+ ((float)total_category_sizes[TagCategoryType]/total_die_size_float)*100.0,
+ ((float)total_category_sizes[TagCategoryProgram]/total_die_size_float)*100.0
+ };
+
+ s->EOL();
+ s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryVariable], total_category_sizes[TagCategoryVariable], total_category_percentages[TagCategoryVariable], "Total for variable related DIEs");
+ s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryType], total_category_sizes[TagCategoryType], total_category_percentages[TagCategoryType], "Total for type related DIEs");
+ s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryProgram], total_category_sizes[TagCategoryProgram], total_category_percentages[TagCategoryProgram], "Total for program related DIEs");
+ s->Printf("\n\n");
+}
+
+typedef struct DumpInfo
+{
+ DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) :
+ strm(init_strm),
+ die_offset(off),
+ recurse_depth(depth),
+ found_depth(UINT_MAX),
+ found_die(false),
+ ancestors()
+ {
+ }
+ Stream* strm;
+ const uint32_t die_offset;
+ const uint32_t recurse_depth;
+ uint32_t found_depth;
+ bool found_die;
+ std::vector<DWARFDebugInfoEntry> ancestors;
+
+ DISALLOW_COPY_AND_ASSIGN(DumpInfo);
+} DumpInfo;
+
+//----------------------------------------------------------------------
+// DumpCallback
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets called each time a compile unit header or debug information
+// entry is successfully parsed.
+//
+// This function dump DWARF information and obey recurse depth and
+// wether a single DIE is to be dumped (or all of the data).
+//----------------------------------------------------------------------
+static dw_offset_t DumpCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ DumpInfo* dumpInfo = (DumpInfo*)userData;
+
+ const DWARFCompileUnit* cu = cu_sp.get();
+
+ Stream *s = dumpInfo->strm;
+ bool show_parents = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_ShowAncestors);
+
+ if (die)
+ {
+ // Are we dumping everything?
+ if (dumpInfo->die_offset == DW_INVALID_OFFSET)
+ {
+ // Yes we are dumping everything. Obey our recurse level though
+ if (curr_depth < dumpInfo->recurse_depth)
+ die->Dump(dwarf2Data, cu, s, 0);
+ }
+ else
+ {
+ // We are dumping a specific DIE entry by offset
+ if (dumpInfo->die_offset == die->GetOffset())
+ {
+ // We found the DIE we were looking for, dump it!
+ if (show_parents)
+ {
+ s->SetIndentLevel(0);
+ const uint32_t num_ancestors = dumpInfo->ancestors.size();
+ if (num_ancestors > 0)
+ {
+ for (uint32_t i=0; i<num_ancestors-1; ++i)
+ {
+ dumpInfo->ancestors[i].Dump(dwarf2Data, cu, s, 0);
+ s->IndentMore();
+ }
+ }
+ }
+
+ dumpInfo->found_depth = curr_depth;
+
+ die->Dump(dwarf2Data, cu, s, 0);
+
+ // Note that we found the DIE we were looking for
+ dumpInfo->found_die = true;
+
+ // Since we are dumping a single DIE, if there are no children we are done!
+ if (!die->HasChildren() || dumpInfo->recurse_depth == 0)
+ return DW_INVALID_OFFSET; // Return an invalid address to end parsing
+ }
+ else if (dumpInfo->found_die)
+ {
+ // Are we done with all the children?
+ if (curr_depth <= dumpInfo->found_depth)
+ return DW_INVALID_OFFSET;
+
+ // We have already found our DIE and are printing it's children. Obey
+ // our recurse depth and return an invalid offset if we get done
+ // dumping all the the children
+ if (dumpInfo->recurse_depth == UINT_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth)
+ die->Dump(dwarf2Data, cu, s, 0);
+ }
+ else if (dumpInfo->die_offset > die->GetOffset())
+ {
+ if (show_parents)
+ dumpInfo->ancestors.back() = *die;
+ }
+ }
+
+ // Keep up with our indent level
+ if (die->IsNULL())
+ {
+ if (show_parents)
+ dumpInfo->ancestors.pop_back();
+
+ if (curr_depth <= 1)
+ return cu->GetNextCompileUnitOffset();
+ else
+ s->IndentLess();
+ }
+ else if (die->HasChildren())
+ {
+ if (show_parents)
+ {
+ DWARFDebugInfoEntry null_die;
+ dumpInfo->ancestors.push_back(null_die);
+ }
+ s->IndentMore();
+ }
+ }
+ else
+ {
+ if (cu == NULL)
+ s->PutCString("NULL - cu");
+ // We have a compile unit, reset our indent level to zero just in case
+ s->SetIndentLevel(0);
+
+ // See if we are dumping everything?
+ if (dumpInfo->die_offset == DW_INVALID_OFFSET)
+ {
+ // We are dumping everything
+ cu->Dump(s);
+ return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit
+ }
+ else
+ {
+ if (show_parents)
+ {
+ dumpInfo->ancestors.clear();
+ dumpInfo->ancestors.resize(1);
+ }
+
+ // We are dumping only a single DIE possibly with it's children and
+ // we must find it's compile unit before we can dump it properly
+ if (dumpInfo->die_offset < cu->GetFirstDIEOffset())
+ {
+ // Not found, maybe the DIE offset provided wasn't correct?
+ // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl;
+ return DW_INVALID_OFFSET;
+ }
+ else
+ {
+ // See if the DIE is in this compile unit?
+ if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset())
+ {
+ // This DIE is in this compile unit!
+ if (s->GetVerbose())
+ cu->Dump(s); // Dump the compile unit for the DIE in verbose mode
+
+ return next_offset;
+ // // We found our compile unit that contains our DIE, just skip to dumping the requested DIE...
+ // return dumpInfo->die_offset;
+ }
+ else
+ {
+ // Skip to the next compile unit as the DIE isn't in the current one!
+ return cu->GetNextCompileUnitOffset();
+ }
+ }
+ }
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dump the information in the .debug_info section to the specified
+// ostream. If die_offset is valid, a single DIE will be dumped. If the
+// die_offset is invalid, all the DWARF information will be dumped. Both
+// cases will obey a "recurse_depth" or how deep to traverse into the
+// children of each DIE entry. A recurse_depth of zero will dump all
+// compile unit headers. A recurse_depth of 1 will dump all compile unit
+// headers and the DW_TAG_compile unit tags. A depth of 2 will also
+// dump all types and functions.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Dump
+(
+ Stream *s,
+ SymbolFileDWARF* dwarf2Data,
+ const uint32_t die_offset,
+ const uint32_t recurse_depth
+)
+{
+ DumpInfo dumpInfo(s, die_offset, recurse_depth);
+ s->PutCString(".debug_info contents");
+ if (dwarf2Data->get_debug_info_data().GetByteSize() > 0)
+ {
+ if (die_offset == DW_INVALID_OFFSET)
+ s->PutCString(":\n");
+ else
+ {
+ s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset);
+ if (recurse_depth != UINT_MAX)
+ s->Printf(" recursing %u levels deep.", recurse_depth);
+ s->EOL();
+ }
+ }
+ else
+ {
+ s->PutCString(": < EMPTY >\n");
+ return;
+ }
+ DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo);
+}
+
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dump the contents of this DWARFDebugInfo object as has been parsed
+// and/or modified after it has been parsed.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Dump (Stream *s, const uint32_t die_offset, const uint32_t recurse_depth)
+{
+ DumpInfo dumpInfo(s, die_offset, recurse_depth);
+
+ s->PutCString("Dumping .debug_info section from internal representation\n");
+
+ CompileUnitColl::const_iterator pos;
+ uint32_t curr_depth = 0;
+ ParseCompileUnitHeadersIfNeeded();
+ for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos)
+ {
+ const DWARFCompileUnitSP& cu_sp = *pos;
+ DumpCallback(m_dwarf2Data, (DWARFCompileUnitSP&)cu_sp, NULL, 0, curr_depth, &dumpInfo);
+ cu_sp->DIE()->Dump(m_dwarf2Data, cu_sp.get(), s, recurse_depth);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// FindCallbackString
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets called each time a compile unit header or debug information
+// entry is successfully parsed.
+//
+// This function will find the die_offset of any items whose DW_AT_name
+// matches the given string
+//----------------------------------------------------------------------
+typedef struct FindCallbackStringInfoTag
+{
+ const char* name;
+ bool ignore_case;
+ RegularExpression* regex;
+ vector<dw_offset_t>& die_offsets;
+} FindCallbackStringInfo;
+
+static dw_offset_t FindCallbackString
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData;
+ const DWARFCompileUnit* cu = cu_sp.get();
+
+ if (die)
+ {
+ const char* die_name = die->GetName(dwarf2Data, cu);
+ if (die_name)
+ {
+ if (info->regex)
+ {
+ if (info->regex->Execute(die_name))
+ info->die_offsets.push_back(die->GetOffset());
+ }
+ else
+ {
+ if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0)
+ info->die_offsets.push_back(die->GetOffset());
+ }
+ }
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// Find
+//
+// Finds all DIE that have a specific DW_AT_name attribute by manually
+// searching through the debug information (not using the
+// .debug_pubnames section). The string must match the entire name
+// and case sensitive searches are an option.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::Find(const char* name, bool ignore_case, vector<dw_offset_t>& die_offsets) const
+{
+ die_offsets.clear();
+ if (name && name[0])
+ {
+ FindCallbackStringInfo info = { name, ignore_case, NULL, die_offsets };
+ DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
+ }
+ return !die_offsets.empty();
+}
+
+//----------------------------------------------------------------------
+// Find
+//
+// Finds all DIE that have a specific DW_AT_name attribute by manually
+// searching through the debug information (not using the
+// .debug_pubnames section). The string must match the supplied regular
+// expression.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::Find(RegularExpression& re, vector<dw_offset_t>& die_offsets) const
+{
+ die_offsets.clear();
+ FindCallbackStringInfo info = { NULL, false, &re, die_offsets };
+ DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
+ return !die_offsets.empty();
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
new file mode 100644
index 0000000..f506a3d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -0,0 +1,86 @@
+//===-- DWARFDebugInfo.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_DWARFDebugInfo_h_
+#define SymbolFileDWARF_DWARFDebugInfo_h_
+
+#include <vector>
+#include <map>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-private.h"
+#include "SymbolFileDWARF.h"
+
+typedef std::multimap<const char*, dw_offset_t, CStringCompareFunctionObject> CStringToDIEMap;
+typedef CStringToDIEMap::iterator CStringToDIEMapIter;
+typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter;
+
+typedef lldb::SharedPtr<DWARFCompileUnit>::Type DWARFCompileUnitSP;
+
+class DWARFDebugInfo
+{
+public:
+ typedef dw_offset_t (*Callback)(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_shared_ptr,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t depth,
+ void* userData);
+
+ DWARFDebugInfo();
+ void SetDwarfData(SymbolFileDWARF* dwarf2Data);
+ bool BuildFunctionAddressRangeTable(DWARFDebugAranges* debug_aranges);
+
+ bool LookupAddress(
+ const dw_addr_t address,
+ const dw_offset_t cu_offset, // Can be valid (find in .debug_aranges), or DW_INVALID_OFFSET if we need to search manually
+ DWARFCompileUnitSP& cu_shared_ptr,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ void AddCompileUnit(DWARFCompileUnitSP& cu);
+ uint32_t GetNumCompileUnits();
+ DWARFCompileUnit* GetCompileUnitAtIndex(uint32_t idx);
+ DWARFCompileUnitSP GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr = NULL);
+ DWARFCompileUnitSP GetCompileUnitContainingDIE(dw_offset_t die_offset);
+
+ DWARFDebugInfoEntry* GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
+ const DWARFDebugInfoEntry* GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
+
+ void Dump(lldb_private::Stream *s, const uint32_t die_offset, const uint32_t recurse_depth);
+ static void Parse(SymbolFileDWARF* parser, Callback callback, void* userData);
+ static void Verify(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data);
+ static void Dump(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data, const uint32_t die_offset, const uint32_t recurse_depth);
+ bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const;
+ bool Find(lldb_private::RegularExpression& re, std::vector<dw_offset_t>& die_offsets) const;
+
+ enum
+ {
+ eDumpFlag_Verbose = (1<<0), // Verbose dumping
+ eDumpFlag_ShowForm = (1<<1), // Show the DW_form type
+ eDumpFlag_EnglishyNames = (1<<2), // Show the DW_TAG, DW_AT and DW_FORM types in more englishy names instead of as DWARF definitions values
+ eDumpFlag_ShowAncestors = (1<<3) // Show all parent DIEs when dumping single DIEs
+ };
+
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ typedef std::vector<DWARFCompileUnitSP> CompileUnitColl;
+
+ CompileUnitColl m_compile_units;
+
+private:
+ // All parsing needs to be done partially any managed by this class as accessors are called.
+ void ParseCompileUnitHeadersIfNeeded();
+
+ DISALLOW_COPY_AND_ASSIGN (DWARFDebugInfo);
+};
+
+#endif // SymbolFileDWARF_DWARFDebugInfo_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 0000000..19eef06
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,1929 @@
+//===-- DWARFDebugInfoEntry.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugInfoEntry.h"
+
+#include <assert.h>
+
+#include <algorithm>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "DWARFCompileUnit.h"
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFLocationDescription.h"
+#include "DWARFLocationList.h"
+#include "DWARFDebugRanges.h"
+
+using namespace lldb_private;
+using namespace std;
+extern int g_verbose;
+
+
+
+DWARFDebugInfoEntry::Attributes::Attributes() :
+ m_infos()
+{
+ m_infos.reserve(20);
+}
+
+DWARFDebugInfoEntry::Attributes::~Attributes()
+{
+}
+
+
+uint32_t
+DWARFDebugInfoEntry::Attributes::FindAttributeIndex(dw_attr_t attr) const
+{
+ std::vector<Info>::const_iterator end = m_infos.end();
+ std::vector<Info>::const_iterator beg = m_infos.begin();
+ std::vector<Info>::const_iterator pos;
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->attr == attr)
+ return std::distance(beg, pos);
+ }
+ return UINT_MAX;
+}
+
+void
+DWARFDebugInfoEntry::Attributes::Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form)
+{
+ Info info = { cu, attr_die_offset, attr, form };
+ m_infos.push_back(info);
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::ContainsAttribute(dw_attr_t attr) const
+{
+ return FindAttributeIndex(attr) != UINT_MAX;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr)
+{
+ uint32_t attr_index = FindAttributeIndex(attr);
+ if (attr_index != UINT_MAX)
+ {
+ m_infos.erase(m_infos.begin() + attr_index);
+ return true;
+ }
+ return false;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const
+{
+ form_value.SetForm(FormAtIndex(i));
+ dw_offset_t offset = DIEOffsetAtIndex(i);
+ return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i));
+}
+
+uint64_t
+DWARFDebugInfoEntry::Attributes::FormValueAsUnsignedAtIndex(SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const
+{
+ DWARFFormValue form_value;
+ if (ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ return form_value.Reference(CompileUnitAtIndex(i));
+ return fail_value;
+}
+
+
+//----------------------------------------------------------------------
+// Extract
+//
+// Extract a debug info entry for a given compile unit from the
+// .debug_info and .debug_abbrev data within the SymbolFileDWARF class
+// starting at the given offset
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::Extract
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ uint32_t* offset_ptr
+)
+{
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+// const DataExtractor& debug_str_data = dwarf2Data->get_debug_str_data();
+ const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset();
+ const uint8_t cu_addr_size = cu->GetAddressByteSize();
+ uint32_t offset = *offset_ptr;
+// if (offset >= cu_end_offset)
+// Log::Error("DIE at offset 0x%8.8x is beyond the end of the current compile unit (0x%8.8x)", m_offset, cu_end_offset);
+ if ((offset < cu_end_offset) && debug_info_data.ValidOffset(offset))
+ {
+ m_offset = offset;
+
+ dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset);
+
+ if (abbrCode)
+ {
+ m_abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(abbrCode);
+
+ if (m_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+
+ bool isCompileUnitTag = tag == DW_TAG_compile_unit;
+ if (cu && isCompileUnitTag)
+ ((DWARFCompileUnit*)cu)->SetBaseAddress(0);
+
+ // Skip all data in the .debug_info for the attributes
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+
+ if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc)))
+ {
+ DWARFFormValue form_value(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc)
+ ((DWARFCompileUnit*)cu)->SetBaseAddress(form_value.Unsigned());
+ }
+ }
+ else
+ {
+die_extract_indirect_form:
+ register uint32_t form_size = 0;
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_block : form_size = debug_info_data.GetULEB128(&offset); break;
+ case DW_FORM_block1 : form_size = debug_info_data.GetU8(&offset); break;
+ case DW_FORM_block2 : form_size = debug_info_data.GetU16(&offset); break;
+ case DW_FORM_block4 : form_size = debug_info_data.GetU32(&offset); break;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string :
+ {
+// const char *s =
+ debug_info_data.GetCStr(&offset);
+// switch (attr)
+// {
+// case DW_AT_name: m_name = s; break;
+// case DW_AT_MIPS_linkage_name: m_linkage_name = s; break;
+// default: break;
+// }
+ }
+ break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ case DW_FORM_ref_addr :
+ form_size = cu_addr_size;
+ break;
+
+ // 1 byte values
+ case DW_FORM_data1 :
+ case DW_FORM_flag :
+ case DW_FORM_ref1 :
+ form_size = 1;
+ break;
+
+ // 2 byte values
+ case DW_FORM_data2 :
+ case DW_FORM_ref2 :
+ form_size = 2;
+ break;
+
+ // 4 byte values
+ case DW_FORM_strp :
+// switch (attr)
+// {
+// case DW_AT_name:
+// m_name = debug_str_data.PeekCStr(debug_info_data.GetU32(&offset));
+// break;
+// case DW_AT_MIPS_linkage_name:
+// m_linkage_name = debug_str_data.PeekCStr(debug_info_data.GetU32(&offset));
+// break;
+//
+// default:
+ form_size = 4;
+// break;
+// }
+ break;
+
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ // case DW_FORM_APPLE_db_str:
+ case DW_FORM_sdata :
+ case DW_FORM_udata :
+ case DW_FORM_ref_udata :
+ debug_info_data.Skip_LEB128(&offset);
+ break;
+
+ case DW_FORM_indirect :
+ form = debug_info_data.GetULEB128(&offset);
+ goto die_extract_indirect_form;
+
+ default:
+ *offset_ptr = offset;
+ return false;
+ }
+
+ offset += form_size;
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ }
+ else
+ {
+ m_abbrevDecl = NULL;
+ *offset_ptr = offset;
+ return true; // NULL debug tag entry
+ }
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+// AppendDependentDIES()
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::AppendDependentDIES
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const bool add_children,
+ DWARFDIECollection& dependent_dies
+) const
+{
+ // Add this object's DIE offset
+ // The line below is the only place that should add a die to the
+ // dependent_dies collection as we have to be careful of recursion!
+ if ( !dependent_dies.Insert(this) )
+ return false; // This DIE already exists in the collection, nothing to do!
+
+ //DEBUG_PRINTF(" dependent_dies.Insert(0x%8.8x)\n", GetOffset());///
+
+ if (m_abbrevDecl)
+ {
+ // Keep adding parent DIE offsets as long as the offsets do not
+ // already exist in the collection
+ const DWARFDebugInfoEntry* die = GetParent();
+ while ( die && die->AppendDependentDIES(dwarf2Data, cu, false, dependent_dies) )
+ die = die->GetParent();
+
+ bool add_non_subprogram_children = false;
+ bool add_children_override = false;
+
+ if (!add_children)
+ {
+ switch (m_abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: break;
+ case DW_TAG_class_type: add_non_subprogram_children = true; break;
+ case DW_TAG_entry_point: break;
+ case DW_TAG_enumeration_type: break;
+ case DW_TAG_formal_parameter: break;
+ case DW_TAG_imported_declaration: break;
+ case DW_TAG_label: break;
+ case DW_TAG_lexical_block: add_children_override = true; break;
+ case DW_TAG_member: break;
+ case DW_TAG_pointer_type: break;
+ case DW_TAG_reference_type: break;
+ case DW_TAG_compile_unit: break;
+ case DW_TAG_string_type: break;
+ case DW_TAG_structure_type: add_non_subprogram_children = true; break;
+ case DW_TAG_subroutine_type: add_children_override = true; break;
+ case DW_TAG_typedef: break;
+ case DW_TAG_union_type: add_non_subprogram_children = true; break;
+ case DW_TAG_unspecified_parameters: break;
+ case DW_TAG_variant: break;
+ case DW_TAG_common_block: break;
+ case DW_TAG_common_inclusion: break;
+ case DW_TAG_inheritance: break;
+ case DW_TAG_inlined_subroutine: break;
+ case DW_TAG_module: break;
+ case DW_TAG_ptr_to_member_type: break;
+ case DW_TAG_set_type: break;
+ case DW_TAG_subrange_type: break;
+ case DW_TAG_with_stmt: break;
+ case DW_TAG_access_declaration: break;
+ case DW_TAG_base_type: break;
+ case DW_TAG_catch_block: break;
+ case DW_TAG_const_type: break;
+ case DW_TAG_constant: break;
+ case DW_TAG_enumerator: break;
+ case DW_TAG_file_type: break;
+ case DW_TAG_friend: break;
+ case DW_TAG_namelist: break;
+ case DW_TAG_namelist_item: break;
+ case DW_TAG_packed_type: break;
+ case DW_TAG_subprogram: add_children_override = true; break;
+ case DW_TAG_template_type_parameter: break;
+ case DW_TAG_template_value_parameter: break;
+ case DW_TAG_thrown_type: break;
+ case DW_TAG_try_block: break;
+ case DW_TAG_variant_part: break;
+ case DW_TAG_variable: break;
+ case DW_TAG_volatile_type: break;
+ case DW_TAG_dwarf_procedure: break;
+ case DW_TAG_restrict_type: break;
+ case DW_TAG_interface_type: break;
+ case DW_TAG_namespace: break;
+ case DW_TAG_imported_module: break;
+ case DW_TAG_unspecified_type: break;
+ case DW_TAG_partial_unit: break;
+ case DW_TAG_imported_unit: break;
+ case DW_TAG_shared_type: break;
+ }
+ }
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_offset_t offset = GetOffset();
+ debug_info_data.Skip_LEB128(&offset); // Skip abbreviation code
+
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+ DWARFFormValue form_value(form);
+
+ switch (attr)
+ {
+ // All cases that use refer to another DIE should use this case
+ // without
+ // having to check the FORM of the attribute to tell if it refers to another
+ // DIE
+ case DW_AT_abstract_origin:
+ case DW_AT_import:
+ case DW_AT_discr:
+ case DW_AT_containing_type:
+ case DW_AT_base_types:
+ case DW_AT_friend:
+ case DW_AT_specification:
+ case DW_AT_type:
+ case DW_AT_common_reference:
+ case DW_AT_default_value:
+ {
+ form_value.ExtractValue(debug_info_data, &offset, cu);
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* ref_die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr);
+ if (ref_die)
+ ref_die->AppendDependentDIES(dwarf2Data, cu_sp_ptr.get(), true, dependent_dies);
+ }
+ break;
+
+ default:
+ if (attr != DW_AT_sibling)
+ {
+ switch (form_value.Form())
+ {
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+// Log::WarningVerbose("DWARFDebugInfoEntry::AppendDependentDIES() -- check on this item %s: attr = %s form = %s",
+// DW_TAG_value_to_name(m_abbrevDecl->Tag()),
+// DW_AT_value_to_name(attr),
+// DW_FORM_value_to_name(form));
+ break;
+ }
+ }
+ form_value.SkipValue(debug_info_data, &offset, cu);
+ break;
+ }
+ }
+
+ if (m_abbrevDecl->HasChildren())
+ {
+ const DWARFDebugInfoEntry* child;
+ for (child = GetFirstChild(); child != NULL; child = child->GetSibling())
+ {
+ bool add = add_children || add_children_override;
+
+ if (!add)
+ {
+ if (add_non_subprogram_children)
+ {
+ // add_non_subprogram_children is used for classes and structs
+ // that may contain children that are the member variables that
+ // may have functions as children and whom may add the class or
+ // struct by adding their parent. We don't want to add any
+ // functions though since they may have been optimized out. But
+ // we do need to watch for declarations and keep them.
+ if (child->Tag() == DW_TAG_subprogram)
+ {
+ // Check if this subprogram TAG had a DW_AT_declaration attribute set to 1.
+ // If so we need to include this DIE so that we always have a complete view
+ // of a class definition so debuggers can track down any weak symbols that
+ // may not have had weak definition entries.
+ if (child->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_declaration, 0) == 1)
+ add = true;
+ }
+ else
+ {
+ // Add all other items inside a class/struct
+ add = true;
+ }
+ }
+ else
+ {
+ // We don't need to add this child, only add it if it's a NULL tag
+ add = child->IsNULL();
+ }
+ }
+
+ if (add)
+ child->AppendDependentDIES(dwarf2Data, cu, true, dependent_dies);
+ }
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------
+// DumpAncestry
+//
+// Dumps all of a debug information entries parents up until oldest and
+// all of it's attributes to the specified stream.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::DumpAncestry
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* oldest,
+ Stream *s,
+ uint32_t recurse_depth
+) const
+{
+ const DWARFDebugInfoEntry* parent = GetParent();
+ if (parent && parent != oldest)
+ parent->DumpAncestry(dwarf2Data, cu, oldest, s, 0);
+ Dump(dwarf2Data, cu, s, recurse_depth);
+}
+
+//----------------------------------------------------------------------
+// Compare two DIE by comparing all their attributes values, and
+// following all DW_FORM_ref attributes and comparing their contents as
+// well (except for DW_AT_sibling attributes.
+//
+// DWARFDebugInfoEntry::CompareState compare_state;
+// int result = DWARFDebugInfoEntry::Compare(this, 0x00017ccb, 0x0001eb2b, compare_state, false, true);
+//----------------------------------------------------------------------
+int
+DWARFDebugInfoEntry::Compare
+(
+ SymbolFileDWARF* dwarf2Data,
+ dw_offset_t a_die_offset,
+ dw_offset_t b_die_offset,
+ CompareState &compare_state,
+ bool compare_siblings,
+ bool compare_children
+)
+{
+ if (a_die_offset == b_die_offset)
+ return 0;
+
+ DWARFCompileUnitSP a_cu_sp;
+ DWARFCompileUnitSP b_cu_sp;
+ const DWARFDebugInfoEntry* a_die = dwarf2Data->DebugInfo()->GetDIEPtr(a_die_offset, &a_cu_sp);
+ const DWARFDebugInfoEntry* b_die = dwarf2Data->DebugInfo()->GetDIEPtr(b_die_offset, &b_cu_sp);
+
+ return Compare(dwarf2Data, a_cu_sp.get(), a_die, b_cu_sp.get(), b_die, compare_state, compare_siblings, compare_children);
+}
+
+int
+DWARFDebugInfoEntry::Compare
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die,
+ DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die,
+ CompareState &compare_state,
+ bool compare_siblings,
+ bool compare_children
+)
+{
+ if (a_die == b_die)
+ return 0;
+
+ if (!compare_state.AddTypePair(a_die->GetOffset(), b_die->GetOffset()))
+ {
+ // We are already comparing both of these types, so let
+ // compares complete for the real result
+ return 0;
+ }
+
+ //printf("DWARFDebugInfoEntry::Compare(0x%8.8x, 0x%8.8x)\n", a_die->GetOffset(), b_die->GetOffset());
+
+ // Do we have two valid DIEs?
+ if (a_die && b_die)
+ {
+ // Both DIE are valid
+ int result = 0;
+
+ const dw_tag_t a_tag = a_die->Tag();
+ const dw_tag_t b_tag = b_die->Tag();
+ if (a_tag == 0 && b_tag == 0)
+ return 0;
+
+ //printf(" comparing tags: %s and %s\n", DW_TAG_value_to_name(a_tag), DW_TAG_value_to_name(b_tag));
+
+ if (a_tag < b_tag)
+ return -1;
+ else if (a_tag > b_tag)
+ return 1;
+
+ DWARFDebugInfoEntry::Attributes a_attrs;
+ DWARFDebugInfoEntry::Attributes b_attrs;
+ size_t a_attr_count = a_die->GetAttributes(dwarf2Data, a_cu, a_attrs);
+ size_t b_attr_count = b_die->GetAttributes(dwarf2Data, b_cu, b_attrs);
+ if (a_attr_count != b_attr_count)
+ {
+ a_attrs.RemoveAttribute(DW_AT_sibling);
+ b_attrs.RemoveAttribute(DW_AT_sibling);
+ }
+
+ a_attr_count = a_attrs.Size();
+ b_attr_count = b_attrs.Size();
+
+ DWARFFormValue a_form_value;
+ DWARFFormValue b_form_value;
+
+ if (a_attr_count != b_attr_count)
+ {
+ uint32_t is_decl_index = a_attrs.FindAttributeIndex(DW_AT_declaration);
+ uint32_t a_name_index = UINT_MAX;
+ uint32_t b_name_index = UINT_MAX;
+ if (is_decl_index != UINT_MAX)
+ {
+ if (a_attr_count == 2)
+ {
+ a_name_index = a_attrs.FindAttributeIndex(DW_AT_name);
+ b_name_index = b_attrs.FindAttributeIndex(DW_AT_name);
+ }
+ }
+ else
+ {
+ is_decl_index = b_attrs.FindAttributeIndex(DW_AT_declaration);
+ if (is_decl_index != UINT_MAX && a_attr_count == 2)
+ {
+ a_name_index = a_attrs.FindAttributeIndex(DW_AT_name);
+ b_name_index = b_attrs.FindAttributeIndex(DW_AT_name);
+ }
+ }
+ if (a_name_index != UINT_MAX && b_name_index != UINT_MAX)
+ {
+ if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, a_name_index, a_form_value) &&
+ b_attrs.ExtractFormValueAtIndex(dwarf2Data, b_name_index, b_form_value))
+ {
+ result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, &dwarf2Data->get_debug_str_data());
+ if (result == 0)
+ {
+ a_attr_count = b_attr_count = 0;
+ compare_children = false;
+ }
+ }
+ }
+ }
+
+ if (a_attr_count < b_attr_count)
+ return -1;
+ if (a_attr_count > b_attr_count)
+ return 1;
+
+
+ // The number of attributes are the same...
+ if (a_attr_count > 0)
+ {
+ const DataExtractor* debug_str_data_ptr = &dwarf2Data->get_debug_str_data();
+
+ uint32_t i;
+ for (i=0; i<a_attr_count; ++i)
+ {
+ const dw_attr_t a_attr = a_attrs.AttributeAtIndex(i);
+ const dw_attr_t b_attr = b_attrs.AttributeAtIndex(i);
+ //printf(" comparing attributes\n\t\t0x%8.8x: %s %s\t\t0x%8.8x: %s %s\n",
+ // a_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(a_attrs.FormAtIndex(i)), DW_AT_value_to_name(a_attr),
+ // b_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(b_attrs.FormAtIndex(i)), DW_AT_value_to_name(b_attr));
+
+ if (a_attr < b_attr)
+ return -1;
+ else if (a_attr > b_attr)
+ return 1;
+
+ switch (a_attr)
+ {
+ // Since we call a form of GetAttributes which inlines the
+ // attributes from DW_AT_abstract_origin and DW_AT_specification
+ // we don't care if their values mismatch...
+ case DW_AT_abstract_origin:
+ case DW_AT_specification:
+ case DW_AT_sibling:
+ case DW_AT_containing_type:
+ //printf(" action = IGNORE\n");
+ result = 0;
+ break; // ignore
+
+ default:
+ if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, i, a_form_value) &&
+ b_attrs.ExtractFormValueAtIndex(dwarf2Data, i, b_form_value))
+ result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, debug_str_data_ptr);
+ break;
+ }
+
+ //printf("\t result = %i\n", result);
+
+ if (result != 0)
+ {
+ // Attributes weren't equal, lets see if we care?
+ switch (a_attr)
+ {
+ case DW_AT_decl_file:
+ // TODO: add the ability to compare files in two different compile units
+ if (a_cu == b_cu)
+ {
+ //printf(" action = RETURN RESULT\n");
+ return result; // Only return the compare results when the compile units are the same and the decl_file attributes can be compared
+ }
+ else
+ {
+ result = 0;
+ //printf(" action = IGNORE\n");
+ }
+ break;
+
+ default:
+ switch (a_attrs.FormAtIndex(i))
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ case DW_FORM_ref_addr:
+ //printf(" action = COMPARE DIEs 0x%8.8x 0x%8.8x\n", (dw_offset_t)a_form_value.Reference(a_cu), (dw_offset_t)b_form_value.Reference(b_cu));
+ // These attribute values refer to other DIEs, so lets compare those instead of their DIE offsets...
+ result = Compare(dwarf2Data, a_form_value.Reference(a_cu), b_form_value.Reference(b_cu), compare_state, false, true);
+ if (result != 0)
+ return result;
+ break;
+
+ default:
+ // We do care that they were different, return this result...
+ //printf(" action = RETURN RESULT\n");
+ return result;
+ }
+ }
+ }
+ }
+ }
+ //printf(" SUCCESS\n\t\t0x%8.8x: %s\n\t\t0x%8.8x: %s\n", a_die->GetOffset(), DW_TAG_value_to_name(a_tag), b_die->GetOffset(), DW_TAG_value_to_name(b_tag));
+
+ if (compare_children)
+ {
+ bool a_has_children = a_die->HasChildren();
+ bool b_has_children = b_die->HasChildren();
+ if (a_has_children == b_has_children)
+ {
+ // Both either have kids or don't
+ if (a_has_children)
+ result = Compare( dwarf2Data,
+ a_cu, a_die->GetFirstChild(),
+ b_cu, b_die->GetFirstChild(),
+ compare_state, true, compare_children);
+ else
+ result = 0;
+ }
+ else if (!a_has_children)
+ result = -1; // A doesn't have kids, but B does
+ else
+ result = 1; // A has kids, but B doesn't
+ }
+
+ if (compare_siblings)
+ {
+ result = Compare( dwarf2Data,
+ a_cu, a_die->GetSibling(),
+ b_cu, b_die->GetSibling(),
+ compare_state, true, compare_children);
+ }
+
+ return result;
+ }
+
+ if (a_die == NULL)
+ return -1; // a_die is NULL, yet b_die is non-NULL
+ else
+ return 1; // a_die is non-NULL, yet b_die is NULL
+
+}
+
+//
+//int
+//DWARFDebugInfoEntry::Compare
+//(
+// SymbolFileDWARF* dwarf2Data,
+// const DWARFCompileUnit* cu_a,
+// const DWARFDebugInfoEntry* die_a,
+// const DWARFCompileUnit* cu_a,
+// const DWARFDebugInfoEntry* die_b,
+// CompareState &compare_state
+//)
+//{
+//}
+
+//----------------------------------------------------------------------
+// GetDIENamesAndRanges
+//
+// Gets the valid address ranges for a given DIE by looking for a
+// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges
+// attributes.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetDIENamesAndRanges
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const char * &name,
+ const char * &mangled,
+ DWARFDebugRanges::RangeList& ranges,
+ int& decl_file,
+ int& decl_line,
+ int& decl_column,
+ int& call_file,
+ int& call_line,
+ int& call_column,
+ DWARFExpression *frame_base
+) const
+{
+ if (dwarf2Data == NULL)
+ return false;
+
+ dw_addr_t lo_pc = DW_INVALID_ADDRESS;
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ std::vector<dw_offset_t> die_offsets;
+ if (m_abbrevDecl)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+ uint32_t offset = m_offset;
+
+ if (!debug_info_data.ValidOffset(offset))
+ return false;
+
+ // Skip the abbreviation code
+ debug_info_data.Skip_LEB128(&offset);
+
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+ DWARFFormValue form_value(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ switch (attr)
+ {
+ case DW_AT_low_pc:
+ case DW_AT_entry_pc:
+ lo_pc = form_value.Unsigned();
+ break;
+
+ case DW_AT_high_pc:
+ hi_pc = form_value.Unsigned();
+ break;
+
+ case DW_AT_ranges:
+ {
+ const DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges();
+ debug_ranges->FindRanges(form_value.Unsigned(), ranges);
+ // All DW_AT_ranges are relative to the base address of the
+ // compile unit. We add the compile unit base address to make
+ // sure all the addresses are properly fixed up.
+ ranges.AddOffset(cu->GetBaseAddress());
+ }
+ break;
+
+ case DW_AT_name:
+ if (name == NULL)
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ if (mangled == NULL)
+ mangled = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ break;
+
+ case DW_AT_abstract_origin:
+ die_offsets.push_back(form_value.Reference(cu));
+ break;
+
+ case DW_AT_specification:
+ die_offsets.push_back(form_value.Reference(cu));
+ break;
+
+ case DW_AT_decl_file:
+ if (decl_file == 0)
+ decl_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_line:
+ if (decl_line == 0)
+ decl_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_column:
+ if (decl_column == 0)
+ decl_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_file:
+ if (call_file == 0)
+ call_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_line:
+ if (call_line == 0)
+ call_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_column:
+ if (call_column == 0)
+ call_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_frame_base:
+ if (frame_base)
+ {
+ if (form_value.BlockData())
+ {
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ frame_base->SetOpcodeData(debug_info_data, block_offset, block_length, NULL);
+ }
+ else
+ {
+ const DataExtractor& debug_loc_data = dwarf2Data->get_debug_loc_data();
+ const dw_offset_t debug_loc_offset = form_value.Unsigned();
+
+ size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset);
+ if (loc_list_length > 0)
+ {
+ Address base_address(cu->GetBaseAddress(), dwarf2Data->GetObjectFile()->GetSectionList());
+ frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length, &base_address);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ size_t numRanges = ranges.Size();
+
+ if (numRanges == 0)
+ {
+ if (lo_pc != DW_INVALID_ADDRESS)
+ {
+ if (hi_pc != DW_INVALID_ADDRESS)
+ ranges.AddRange(lo_pc, hi_pc);
+ else
+ ranges.AddRange(lo_pc, lo_pc);
+ }
+ }
+
+ if (ranges.Size() == 0 || (name == NULL) || (mangled == NULL))
+ {
+ std::vector<dw_offset_t>::const_iterator pos;
+ std::vector<dw_offset_t>::const_iterator end = die_offsets.end();
+ for (pos = die_offsets.begin(); pos != end; ++pos)
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = NULL;
+ dw_offset_t die_offset = *pos;
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ die = dwarf2Data->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr);
+ if (die)
+ die->GetDIENamesAndRanges(dwarf2Data, cu_sp_ptr.get(), name, mangled, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column);
+ }
+ }
+ }
+ return ranges.Size() > 0;
+}
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dumps a debug information entry and all of it's attributes to the
+// specified stream.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::Dump
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ Stream *s,
+ uint32_t recurse_depth
+) const
+{
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+ uint32_t offset = m_offset;
+ bool english = s->GetFlags().IsSet (DWARFDebugInfo::eDumpFlag_EnglishyNames);
+
+ if (debug_info_data.ValidOffset(offset))
+ {
+ dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset);
+
+ s->Printf("\n0x%8.8x: ", m_offset);
+ s->Indent();
+ if (abbrCode)
+ {
+ if (m_abbrevDecl)
+ {
+ if (english)
+ s->PutCString(DW_TAG_value_to_englishy_name(m_abbrevDecl->Tag()));
+ else
+ s->PutCString(DW_TAG_value_to_name(m_abbrevDecl->Tag()));
+ s->Printf( " [%u] %c\n", abbrCode, m_abbrevDecl->HasChildren() ? '*':' ');
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+
+ DumpAttribute(dwarf2Data, cu, debug_info_data, &offset, s, attr, form);
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ if (recurse_depth > 0 && child)
+ {
+ s->IndentMore();
+
+ while (child)
+ {
+ child->Dump(dwarf2Data, cu, s, recurse_depth-1);
+ child = child->GetSibling();
+ }
+ s->IndentLess();
+ }
+ }
+ else
+ s->Printf( "Abbreviation code note found in 'debug_abbrev' class for code: %u\n", abbrCode);
+ }
+ else
+ {
+ s->Printf( "NULL\n");
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpAttribute
+//
+// Dumps a debug information entry attribute along with it's form. Any
+// special display of attributes is done (disassemble location lists,
+// show enumeration values for attributes, etc).
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::DumpAttribute
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DataExtractor& debug_info_data,
+ uint32_t* offset_ptr,
+ Stream *s,
+ dw_attr_t attr,
+ dw_form_t form
+)
+{
+ bool verbose = s->GetVerbose();
+ bool show_form = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_ShowForm);
+ bool english = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_EnglishyNames);
+ const DataExtractor* debug_str_data = dwarf2Data ? &dwarf2Data->get_debug_str_data() : NULL;
+ if (verbose)
+ s->Offset(*offset_ptr);
+ else
+ s->Printf( " ");
+ s->Indent();
+
+ if (english)
+ s->PutCString(DW_AT_value_to_englishy_name(attr));
+ else
+ s->PutCString(DW_AT_value_to_name(attr));
+
+ if (show_form)
+ {
+ s->Printf( "[%s", english ? DW_FORM_value_to_englishy_name(form) : DW_FORM_value_to_name(form));
+ }
+
+ DWARFFormValue form_value(form);
+
+ if (!form_value.ExtractValue(debug_info_data, offset_ptr, cu))
+ return;
+
+ if (show_form)
+ {
+ if (form == DW_FORM_indirect)
+ {
+ s->Printf( " [%s]", english ? DW_FORM_value_to_englishy_name(form_value.Form()) : DW_FORM_value_to_name(form_value.Form()));
+ }
+
+ s->PutCString("] ");
+ }
+
+ s->PutCString("( ");
+
+ // Always dump form value if verbose is enabled
+ if (verbose)
+ {
+ form_value.Dump(s, debug_str_data, cu);
+ }
+
+
+ // Check to see if we have any special attribute formatters
+ switch (attr)
+ {
+ case DW_AT_stmt_list:
+ if ( verbose ) s->PutCString(" ( ");
+ s->Printf( "0x%8.8x", form_value.Unsigned());
+ if ( verbose ) s->PutCString(" )");
+ break;
+
+ case DW_AT_language:
+ if ( verbose ) s->PutCString(" ( ");
+ s->PutCString(DW_LANG_value_to_name(form_value.Unsigned()));
+ if ( verbose ) s->PutCString(" )");
+ break;
+
+ case DW_AT_encoding:
+ if ( verbose ) s->PutCString(" ( ");
+ s->PutCString(DW_ATE_value_to_name(form_value.Unsigned()));
+ if ( verbose ) s->PutCString(" )");
+ break;
+
+ case DW_AT_frame_base:
+ case DW_AT_location:
+ case DW_AT_data_member_location:
+ {
+ const uint8_t* blockData = form_value.BlockData();
+ if (blockData)
+ {
+ if (!verbose)
+ form_value.Dump(s, debug_str_data, cu);
+
+ // Location description is inlined in data in the form value
+ DataExtractor locationData(debug_info_data, (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned());
+ if ( verbose ) s->PutCString(" ( ");
+ print_dwarf_expression (s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false);
+ if ( verbose ) s->PutCString(" )");
+ }
+ else
+ {
+ // We have a location list offset as the value that is
+ // the offset into the .debug_loc section that describes
+ // the value over it's lifetime
+ uint64_t debug_loc_offset = form_value.Unsigned();
+ if (dwarf2Data)
+ {
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ DWARFLocationList::Dump(s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset);
+ }
+ else
+ {
+ if ( !verbose )
+ form_value.Dump(s, NULL, cu);
+ }
+ }
+ }
+ break;
+
+ case DW_AT_abstract_origin:
+ case DW_AT_specification:
+ {
+ uint64_t abstract_die_offset = form_value.Reference(cu);
+ form_value.Dump(s, debug_str_data, cu);
+ // *ostrm_ptr << HEX32 << abstract_die_offset << " ( ";
+ if ( verbose ) s->PutCString(" ( ");
+ GetName(dwarf2Data, cu, abstract_die_offset, s);
+ if ( verbose ) s->PutCString(" )");
+ }
+ break;
+
+ case DW_AT_type:
+ {
+ uint64_t type_die_offset = form_value.Reference(cu);
+ if (!verbose)
+ form_value.Dump(s, debug_str_data, cu);
+ s->PutCString(" ( ");
+ AppendTypeName(dwarf2Data, cu, type_die_offset, s);
+ s->PutCString(" )");
+ }
+ break;
+
+ case DW_AT_ranges:
+ {
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ uint32_t ranges_offset = form_value.Unsigned();
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(), &ranges_offset, base_addr);
+ }
+ break;
+
+ default:
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ break;
+ }
+
+ s->PutCString(" )\n");
+}
+
+//----------------------------------------------------------------------
+// Get all attribute values for a given DIE, including following any
+// specification or abstract origin attributes and including those in
+// the results. Any duplicate attributes will have the first instance
+// take precedence (this can happen for declaration attributes).
+//----------------------------------------------------------------------
+size_t
+DWARFDebugInfoEntry::GetAttributes
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry::Attributes& attributes
+) const
+{
+ if (m_abbrevDecl)
+ {
+ uint32_t offset = GetOffset();
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info_data.Skip_LEB128(&offset);
+
+ const uint32_t num_attributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ DWARFFormValue form_value;
+ for (i=0; i<num_attributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form);
+ attributes.Append(cu, offset, attr, form);
+ if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))
+ {
+ form_value.SetForm(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ const DWARFDebugInfoEntry* die = NULL;
+ dw_offset_t die_offset = form_value.Reference(cu);
+ if (cu->ContainsDIEOffset(die_offset))
+ {
+ die = const_cast<DWARFCompileUnit*>(cu)->GetDIEPtr(die_offset);
+ if (die)
+ die->GetAttributes(dwarf2Data, cu, attributes);
+ }
+ else
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr);
+ if (die)
+ die->GetAttributes(dwarf2Data, cu_sp_ptr.get(), attributes);
+ }
+ }
+ }
+ else
+ {
+ assert(DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu));
+ }
+ }
+ }
+ else
+ {
+ attributes.Clear();
+ }
+ return attributes.Size();
+
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValue
+//
+// Get the value of an attribute and return the .debug_info offset of the
+// attribute if it was properly extracted into form_value, or zero
+// if we fail since an offset of zero is invalid for an attribute (it
+// would be a compile unit header).
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugInfoEntry::GetAttributeValue
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DWARFFormValue& form_value,
+ dw_offset_t* end_attr_offset_ptr
+) const
+{
+ if (m_abbrevDecl)
+ {
+ uint32_t attr_idx = m_abbrevDecl->FindAttributeIndex(attr);
+
+ if (attr_idx != DW_INVALID_INDEX)
+ {
+ uint32_t offset = GetOffset();
+
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info_data.Skip_LEB128(&offset);
+
+ uint32_t idx=0;
+ while (idx<attr_idx)
+ DWARFFormValue::SkipValue(m_abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu);
+
+ const dw_offset_t attr_offset = offset;
+ form_value.SetForm(m_abbrevDecl->GetFormByIndex(idx));
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ if (end_attr_offset_ptr)
+ *end_attr_offset_ptr = offset;
+ return attr_offset;
+ }
+ }
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsString
+//
+// Get the value of an attribute as a string return it. The resulting
+// pointer to the string data exists within the supplied SymbolFileDWARF
+// and will only be available as long as the SymbolFileDWARF is still around
+// and it's content doesn't change.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetAttributeValueAsString
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ const char* fail_value) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsUnsigned
+//
+// Get the value of an attribute as unsigned and return it.
+//----------------------------------------------------------------------
+uint64_t
+DWARFDebugInfoEntry::GetAttributeValueAsUnsigned
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Unsigned();
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsSigned
+//
+// Get the value of an attribute a signed value and return it.
+//----------------------------------------------------------------------
+int64_t
+DWARFDebugInfoEntry::GetAttributeValueAsSigned
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ int64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Signed();
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsReference
+//
+// Get the value of an attribute as reference and fix up and compile
+// unit relative offsets as needed.
+//----------------------------------------------------------------------
+uint64_t
+DWARFDebugInfoEntry::GetAttributeValueAsReference
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Reference(cu);
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsLocation
+//
+// Get the value of an attribute as reference and fix up and compile
+// unit relative offsets as needed.
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugInfoEntry::GetAttributeValueAsLocation
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DataExtractor& location_data,
+ uint32_t &block_size
+) const
+{
+ block_size = 0;
+ DWARFFormValue form_value;
+
+ // Empty out data in case we don't find anything
+ location_data.Clear();
+ dw_offset_t end_addr_offset = DW_INVALID_OFFSET;
+ const dw_offset_t attr_offset = GetAttributeValue(dwarf2Data, cu, attr, form_value, &end_addr_offset);
+ if (attr_offset)
+ {
+ const uint8_t* blockData = form_value.BlockData();
+ if (blockData)
+ {
+ // We have an inlined location list in the .debug_info section
+ const DataExtractor& debug_info = dwarf2Data->get_debug_info_data();
+ dw_offset_t block_offset = blockData - debug_info.GetDataStart();
+ block_size = (end_addr_offset - attr_offset) - form_value.Unsigned();
+ location_data.SetData(debug_info, block_offset, block_size);
+ }
+ else
+ {
+ // We have a location list offset as the value that is
+ // the offset into the .debug_loc section that describes
+ // the value over it's lifetime
+ dw_offset_t debug_loc_offset = form_value.Unsigned();
+ if (dwarf2Data)
+ {
+ assert(dwarf2Data->get_debug_loc_data().GetAddressByteSize() == cu->GetAddressByteSize());
+ return DWARFLocationList::Extract(dwarf2Data->get_debug_loc_data(), &debug_loc_offset, location_data);
+ }
+ }
+ }
+ return attr_offset;
+}
+
+//----------------------------------------------------------------------
+// GetName
+//
+// Get value of the DW_AT_name attribute and return it if one exists,
+// else return NULL.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ return form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// GetMangledName
+//
+// Get value of the DW_AT_MIPS_linkage_name attribute and return it if
+// one exists, else return the value of the DW_AT_name attribute
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetMangledName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ bool substitute_name_allowed
+) const
+{
+ const char* name = NULL;
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+
+ if (substitute_name_allowed && name == NULL)
+ {
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ }
+ return name;
+}
+
+
+//----------------------------------------------------------------------
+// GetPubname
+//
+// Get value the name for a DIE as it should appear for a
+// .debug_pubnames or .debug_pubtypes section.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetPubname
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu
+) const
+{
+ const char* name = NULL;
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value))
+ {
+ // The specification DIE may be in another compile unit so we need
+ // to get a die and its compile unit.
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr);
+ if (die)
+ return die->GetPubname(dwarf2Data, cu_sp_ptr.get());
+ }
+ return name;
+}
+
+
+//----------------------------------------------------------------------
+// GetName
+//
+// Get value of the DW_AT_name attribute for a debug information entry
+// that exists at offset "die_offset" and place that value into the
+// supplied stream object. If the DIE is a NULL object "NULL" is placed
+// into the stream, and if no DW_AT_name attribute exists for the DIE
+// then nothing is printed.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const uint32_t die_offset,
+ Stream *s
+)
+{
+ DWARFDebugInfoEntry die;
+ uint32_t offset = die_offset;
+ if (die.Extract(dwarf2Data, cu, &offset))
+ {
+ if (die.IsNULL())
+ {
+ s->PutCString("NULL");
+ return true;
+ }
+ else
+ {
+ DWARFFormValue form_value;
+ if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ {
+ const char* name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ if (name)
+ {
+ s->PutCString(name);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// AppendTypeName
+//
+// Follows the type name definition down through all needed tags to
+// end up with a fully qualified type name and dump the results to
+// the supplied stream. This is used to show the name of types given
+// a type identifier.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::AppendTypeName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const uint32_t die_offset,
+ Stream *s
+)
+{
+ DWARFDebugInfoEntry die;
+ uint32_t offset = die_offset;
+ if (die.Extract(dwarf2Data, cu, &offset))
+ {
+ if (die.IsNULL())
+ {
+ s->PutCString("NULL");
+ return true;
+ }
+ else
+ {
+ const char* name = die.GetPubname(dwarf2Data, cu);
+ // if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ // name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ if (name)
+ s->PutCString(name);
+ else
+ {
+ bool result = true;
+ const DWARFAbbreviationDeclaration* abbrevDecl = die.GetAbbreviationDeclarationPtr();
+
+ switch (abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: break; // print out a "[]" after printing the full type of the element below
+ case DW_TAG_base_type: s->PutCString("base "); break;
+ case DW_TAG_class_type: s->PutCString("class "); break;
+ case DW_TAG_const_type: s->PutCString("const "); break;
+ case DW_TAG_enumeration_type: s->PutCString("enum "); break;
+ case DW_TAG_file_type: s->PutCString("file "); break;
+ case DW_TAG_interface_type: s->PutCString("interface "); break;
+ case DW_TAG_packed_type: s->PutCString("packed "); break;
+ case DW_TAG_pointer_type: break; // print out a '*' after printing the full type below
+ case DW_TAG_ptr_to_member_type: break; // print out a '*' after printing the full type below
+ case DW_TAG_reference_type: break; // print out a '&' after printing the full type below
+ case DW_TAG_restrict_type: s->PutCString("restrict "); break;
+ case DW_TAG_set_type: s->PutCString("set "); break;
+ case DW_TAG_shared_type: s->PutCString("shared "); break;
+ case DW_TAG_string_type: s->PutCString("string "); break;
+ case DW_TAG_structure_type: s->PutCString("struct "); break;
+ case DW_TAG_subrange_type: s->PutCString("subrange "); break;
+ case DW_TAG_subroutine_type: s->PutCString("function "); break;
+ case DW_TAG_thrown_type: s->PutCString("thrown "); break;
+ case DW_TAG_union_type: s->PutCString("union "); break;
+ case DW_TAG_unspecified_type: s->PutCString("unspecified "); break;
+ case DW_TAG_volatile_type: s->PutCString("volatile "); break;
+ default:
+ return false;
+ }
+
+ // Follow the DW_AT_type if possible
+ DWARFFormValue form_value;
+ if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_type, form_value))
+ {
+ uint64_t next_die_offset = form_value.Reference(cu);
+ result = AppendTypeName(dwarf2Data, cu, next_die_offset, s);
+ }
+
+ switch (abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: s->PutCString("[]"); break;
+ case DW_TAG_pointer_type: s->PutChar('*'); break;
+ case DW_TAG_ptr_to_member_type: s->PutChar('*'); break;
+ case DW_TAG_reference_type: s->PutChar('&'); break;
+ default:
+ break;
+ }
+ return result;
+ }
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// BuildAddressRangeTable
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ if (tag == DW_TAG_subprogram)
+ {
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_INVALID_ADDRESS)
+ {
+ /// printf("BuildAddressRangeTable() 0x%8.8x: %30s: [0x%8.8x - 0x%8.8x)\n", m_offset, DW_TAG_value_to_name(tag), lo_pc, hi_pc);
+ debug_aranges->InsertRange(cu->GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// BuildFunctionAddressRangeTable
+//
+// This function is very similar to the BuildAddressRangeTable function
+// except that the actual DIE offset for the function is placed in the
+// table instead of the compile unit offset (which is the way the
+// standard .debug_aranges section does it).
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildFunctionAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ if (tag == DW_TAG_subprogram)
+ {
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_INVALID_ADDRESS)
+ {
+ // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16llx - 0x%16.16llx)\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY
+ debug_aranges->InsertRange(GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildFunctionAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// LookupAddress
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::LookupAddress
+(
+ const dw_addr_t address,
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die
+)
+{
+ bool found_address = false;
+ if (m_abbrevDecl)
+ {
+ bool check_children = false;
+ bool match_addr_range = false;
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, DW_TAG_value_to_name(tag), address);
+ switch (tag)
+ {
+ case DW_TAG_array_type : break;
+ case DW_TAG_class_type : check_children = true; break;
+ case DW_TAG_entry_point : break;
+ case DW_TAG_enumeration_type : break;
+ case DW_TAG_formal_parameter : break;
+ case DW_TAG_imported_declaration : break;
+ case DW_TAG_label : break;
+ case DW_TAG_lexical_block : check_children = true; match_addr_range = true; break;
+ case DW_TAG_member : break;
+ case DW_TAG_pointer_type : break;
+ case DW_TAG_reference_type : break;
+ case DW_TAG_compile_unit : match_addr_range = true; break;
+ case DW_TAG_string_type : break;
+ case DW_TAG_structure_type : check_children = true; break;
+ case DW_TAG_subroutine_type : break;
+ case DW_TAG_typedef : break;
+ case DW_TAG_union_type : break;
+ case DW_TAG_unspecified_parameters : break;
+ case DW_TAG_variant : break;
+ case DW_TAG_common_block : check_children = true; break;
+ case DW_TAG_common_inclusion : break;
+ case DW_TAG_inheritance : break;
+ case DW_TAG_inlined_subroutine : check_children = true; match_addr_range = true; break;
+ case DW_TAG_module : match_addr_range = true; break;
+ case DW_TAG_ptr_to_member_type : break;
+ case DW_TAG_set_type : break;
+ case DW_TAG_subrange_type : break;
+ case DW_TAG_with_stmt : break;
+ case DW_TAG_access_declaration : break;
+ case DW_TAG_base_type : break;
+ case DW_TAG_catch_block : match_addr_range = true; break;
+ case DW_TAG_const_type : break;
+ case DW_TAG_constant : break;
+ case DW_TAG_enumerator : break;
+ case DW_TAG_file_type : break;
+ case DW_TAG_friend : break;
+ case DW_TAG_namelist : break;
+ case DW_TAG_namelist_item : break;
+ case DW_TAG_packed_type : break;
+ case DW_TAG_subprogram : match_addr_range = true; break;
+ case DW_TAG_template_type_parameter : break;
+ case DW_TAG_template_value_parameter : break;
+ case DW_TAG_thrown_type : break;
+ case DW_TAG_try_block : match_addr_range = true; break;
+ case DW_TAG_variant_part : break;
+ case DW_TAG_variable : break;
+ case DW_TAG_volatile_type : break;
+ case DW_TAG_dwarf_procedure : break;
+ case DW_TAG_restrict_type : break;
+ case DW_TAG_interface_type : break;
+ case DW_TAG_namespace : check_children = true; break;
+ case DW_TAG_imported_module : break;
+ case DW_TAG_unspecified_type : break;
+ case DW_TAG_partial_unit : break;
+ case DW_TAG_imported_unit : break;
+ case DW_TAG_shared_type : break;
+ default: break;
+ }
+
+ if (match_addr_range)
+ {
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ {
+ dw_addr_t hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_INVALID_ADDRESS)
+ {
+ // printf("\n0x%8.8x: %30s: address = 0x%8.8x [0x%8.8x - 0x%8.8x) ", m_offset, DW_TAG_value_to_name(tag), address, lo_pc, hi_pc);
+ if ((lo_pc <= address) && (address < hi_pc))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (tag)
+ {
+ case DW_TAG_compile_unit: // File
+ check_children = ((function_die != NULL) || (block_die != NULL));
+ break;
+
+ case DW_TAG_subprogram: // Function
+ if (function_die)
+ *function_die = this;
+ check_children = (block_die != NULL);
+ break;
+
+ case DW_TAG_inlined_subroutine: // Inlined Function
+ case DW_TAG_lexical_block: // Block { } in code
+ if (block_die)
+ {
+ *block_die = this;
+ check_children = true;
+ }
+ break;
+
+ default:
+ check_children = true;
+ break;
+ }
+ }
+ }
+ else
+ { // compile units may not have a valid high/low pc when there
+ // are address gaps in subtroutines so we must always search
+ // if there is no valid high and low PC
+ check_children = (tag == DW_TAG_compile_unit) && ((function_die != NULL) || (block_die != NULL));
+ }
+ }
+ else
+ {
+ dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET);
+ if (debug_ranges_offset != DW_INVALID_OFFSET)
+ {
+ DWARFDebugRanges::RangeList ranges;
+ DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges();
+ debug_ranges->FindRanges(debug_ranges_offset, ranges);
+ // All DW_AT_ranges are relative to the base address of the
+ // compile unit. We add the compile unit base address to make
+ // sure all the addresses are properly fixed up.
+ ranges.AddOffset(cu->GetBaseAddress());
+ if (ranges.Lookup(address))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (tag)
+ {
+ case DW_TAG_compile_unit: // File
+ check_children = ((function_die != NULL) || (block_die != NULL));
+ break;
+
+ case DW_TAG_subprogram: // Function
+ if (function_die)
+ *function_die = this;
+ check_children = (block_die != NULL);
+ break;
+
+ case DW_TAG_inlined_subroutine: // Inlined Function
+ case DW_TAG_lexical_block: // Block { } in code
+ if (block_die)
+ {
+ *block_die = this;
+ check_children = true;
+ }
+ break;
+
+ default:
+ check_children = true;
+ break;
+ }
+ }
+ else
+ {
+ check_children = false;
+ }
+ }
+ }
+ }
+
+
+ if (check_children)
+ {
+ // printf("checking children\n");
+ DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ if (child->LookupAddress(address, dwarf2Data, cu, function_die, block_die))
+ return true;
+ child = child->GetSibling();
+ }
+ }
+ }
+ return found_address;
+}
+
+
+bool
+DWARFDebugInfoEntry::OffsetLessThan (const DWARFDebugInfoEntry& a, const DWARFDebugInfoEntry& b)
+{
+ return a.GetOffset() < b.GetOffset();
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
new file mode 100644
index 0000000..8340acc
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -0,0 +1,320 @@
+//===-- DWARFDebugInfoEntry.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_DWARFDebugInfoEntry_h_
+#define liblldb_DWARFDebugInfoEntry_h_
+
+#include "SymbolFileDWARF.h"
+#include "DWARFAbbreviationDeclaration.h"
+#include "DWARFDebugRanges.h"
+#include <vector>
+#include <map>
+#include <set>
+
+typedef std::map<const DWARFDebugInfoEntry*, dw_addr_t> DIEToAddressMap;
+typedef DIEToAddressMap::iterator DIEToAddressMapIter;
+typedef DIEToAddressMap::const_iterator DIEToAddressMapConstIter;
+
+typedef std::map<dw_addr_t, const DWARFDebugInfoEntry*> AddressToDIEMap;
+typedef AddressToDIEMap::iterator AddressToDIEMapIter;
+typedef AddressToDIEMap::const_iterator AddressToDIEMapConstIter;
+
+
+typedef std::map<dw_offset_t, dw_offset_t> DIEToDIEMap;
+typedef DIEToDIEMap::iterator DIEToDIEMapIter;
+typedef DIEToDIEMap::const_iterator DIEToDIEMapConstIter;
+
+typedef std::map<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMap;
+typedef UInt32ToDIEMap::iterator UInt32ToDIEMapIter;
+typedef UInt32ToDIEMap::const_iterator UInt32ToDIEMapConstIter;
+
+typedef std::multimap<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMMap;
+typedef UInt32ToDIEMMap::iterator UInt32ToDIEMMapIter;
+typedef UInt32ToDIEMMap::const_iterator UInt32ToDIEMMapConstIter;
+
+class DWARFDebugInfoEntry
+{
+public:
+ typedef std::vector<DWARFDebugInfoEntry> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ typedef std::vector<dw_offset_t> offset_collection;
+ typedef offset_collection::iterator offset_collection_iterator;
+ typedef offset_collection::const_iterator offset_collection_const_iterator;
+
+ class Attributes
+ {
+ public:
+ Attributes();
+ ~Attributes();
+
+ void Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form);
+ const DWARFCompileUnit * CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; }
+ dw_offset_t DIEOffsetAtIndex(uint32_t i) const { return m_infos[i].die_offset; }
+ dw_attr_t AttributeAtIndex(uint32_t i) const { return m_infos[i].attr; }
+ dw_attr_t FormAtIndex(uint32_t i) const { return m_infos[i].form; }
+ bool ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const;
+ uint64_t FormValueAsUnsignedAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const;
+ uint32_t FindAttributeIndex(dw_attr_t attr) const;
+ bool ContainsAttribute(dw_attr_t attr) const;
+ bool RemoveAttribute(dw_attr_t attr);
+ void Clear() { m_infos.clear(); }
+ uint32_t Size() const { return m_infos.size(); }
+
+ protected:
+ struct Info
+ {
+ const DWARFCompileUnit *cu; // Keep the compile unit with each attribute in case we have DW_FORM_ref_addr values
+ dw_offset_t die_offset;
+ dw_attr_t attr;
+ dw_form_t form;
+ };
+ std::vector<Info> m_infos;
+ };
+
+ struct CompareState
+ {
+ CompareState() :
+ die_offset_pairs()
+ {
+ assert(sizeof(dw_offset_t)*2 == sizeof(uint64_t));
+ }
+
+ bool AddTypePair(dw_offset_t a, dw_offset_t b)
+ {
+ uint64_t a_b_offsets = (uint64_t)a << 32 | (uint64_t)b;
+ // Return true if this type was inserted, false otherwise
+ return die_offset_pairs.insert(a_b_offsets).second;
+ }
+ std::set< uint64_t > die_offset_pairs;
+ };
+
+ DWARFDebugInfoEntry():
+ m_offset (DW_INVALID_OFFSET),
+ m_parent_idx (0),
+ m_sibling_idx (0),
+ m_abbrevDecl (NULL),
+ m_user_data (NULL)
+ {
+ }
+
+
+ void BuildAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ void BuildFunctionAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ bool Extract(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_offset_t* offset_ptr);
+
+ bool LookupAddress(
+ const dw_addr_t address,
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ size_t GetAttributes(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry::Attributes& attrs) const;
+
+ dw_offset_t GetAttributeValue(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DWARFFormValue& formValue,
+ dw_offset_t* end_attr_offset_ptr = NULL) const;
+
+ const char* GetAttributeValueAsString(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ const char* fail_value) const;
+
+ uint64_t GetAttributeValueAsUnsigned(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ uint64_t GetAttributeValueAsReference(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ int64_t GetAttributeValueAsSigned(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ int64_t fail_value) const;
+
+ dw_offset_t GetAttributeValueAsLocation(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ lldb_private::DataExtractor& data,
+ uint32_t &block_size) const;
+
+ const char* GetName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu) const;
+
+ const char* GetMangledName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ bool substitute_name_allowed = true) const;
+
+ const char* GetPubname(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu) const;
+
+ static bool GetName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ lldb_private::Stream *s);
+
+ static bool AppendTypeName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ lldb_private::Stream *s);
+
+ static int Compare(
+ SymbolFileDWARF* dwarf2Data,
+ dw_offset_t a_die_offset,
+ dw_offset_t b_die_offset,
+ CompareState &compare_state,
+ bool compare_siblings,
+ bool compare_children);
+
+ static int Compare(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die,
+ DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die,
+ CompareState &compare_state,
+ bool compare_siblings,
+ bool compare_children);
+
+ static bool OffsetLessThan (
+ const DWARFDebugInfoEntry& a,
+ const DWARFDebugInfoEntry& b);
+
+ bool AppendDependentDIES(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const bool add_children,
+ DWARFDIECollection& die_offsets) const;
+
+ void Dump(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ lldb_private::Stream *s,
+ uint32_t recurse_depth) const;
+
+ void DumpAncestry(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* oldest,
+ lldb_private::Stream *s,
+ uint32_t recurse_depth) const;
+
+ static void DumpAttribute(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const lldb_private::DataExtractor& debug_info_data,
+ uint32_t* offset_ptr,
+ lldb_private::Stream *s,
+ dw_attr_t attr,
+ dw_form_t form);
+
+ bool GetDIENamesAndRanges(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const char * &name,
+ const char * &mangled,
+ DWARFDebugRanges::RangeList& rangeList,
+ int& decl_file,
+ int& decl_line,
+ int& decl_column,
+ int& call_file,
+ int& call_line,
+ int& call_column,
+ lldb_private::DWARFExpression *frame_base = NULL) const;
+
+
+ dw_tag_t Tag() const { return m_abbrevDecl ? m_abbrevDecl->Tag() : 0; }
+ bool IsNULL() const { return m_abbrevDecl == NULL; }
+ dw_offset_t GetOffset() const { return m_offset; }
+ void SetOffset(dw_offset_t offset) { m_offset = offset; }
+ uint32_t NumAttributes() const { return m_abbrevDecl ? m_abbrevDecl->NumAttributes() : 0; }
+ bool HasChildren() const { return m_abbrevDecl != NULL && m_abbrevDecl->HasChildren(); }
+
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our parent will be some index behind "this".
+ DWARFDebugInfoEntry* GetParent() { return m_parent_idx > 0 ? this - m_parent_idx : NULL; }
+ const DWARFDebugInfoEntry* GetParent() const { return m_parent_idx > 0 ? this - m_parent_idx : NULL; }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our sibling will be some index after "this".
+ DWARFDebugInfoEntry* GetSibling() { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; }
+ const DWARFDebugInfoEntry* GetSibling() const { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // we don't need to store our child pointer, if we have a child it will
+ // be the next entry in the list...
+ DWARFDebugInfoEntry* GetFirstChild() { return HasChildren() ? this + 1 : NULL; }
+ const DWARFDebugInfoEntry* GetFirstChild() const { return HasChildren() ? this + 1 : NULL; }
+
+ void
+ SetParent (DWARFDebugInfoEntry* parent)
+ {
+ if (parent)
+ {
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our parent will be some index behind "this".
+ m_parent_idx = this - parent;
+ }
+ else
+ m_parent_idx = 0;
+ }
+ void
+ SetSibling (DWARFDebugInfoEntry* sibling)
+ {
+ if (sibling)
+ {
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our sibling will be some index after "this".
+ m_sibling_idx = sibling - this;
+ sibling->SetParent(GetParent());
+ }
+ else
+ m_sibling_idx = 0;
+ }
+ const DWARFAbbreviationDeclaration* GetAbbreviationDeclarationPtr() const { return m_abbrevDecl; }
+
+ void * GetUserData() const { return m_user_data; }
+ void SetUserData(void *d) const { m_user_data = d; }
+protected:
+ dw_offset_t m_offset; // Offset within the .debug_info of the start of this entry
+ uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. If zero this die has no parent
+ uint32_t m_sibling_idx; // How many to add to "this" to get the sibling.
+ const DWARFAbbreviationDeclaration* m_abbrevDecl;
+ mutable void * m_user_data; // Flags for use by the parsers
+};
+
+#endif // liblldb_DWARFDebugInfoEntry_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
new file mode 100644
index 0000000..2b3f39b
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -0,0 +1,1410 @@
+//===-- DWARFDebugLine.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugLine.h"
+
+//#define ENABLE_DEBUG_PRINTF // DO NOT LEAVE THIS DEFINED: DEBUG ONLY!!!
+#include <assert.h>
+
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Timer.h"
+
+#include "SymbolFileDWARF.h"
+#include "LogChannelDWARF.h"
+
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parse all information in the debug_line_data into an internal
+// representation.
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Parse(const DataExtractor& debug_line_data)
+{
+ m_lineTableMap.clear();
+ dw_offset_t offset = 0;
+ LineTable::shared_ptr line_table_sp(new LineTable);
+ while (debug_line_data.ValidOffset(offset))
+ {
+ const uint32_t debug_line_offset = offset;
+
+ if (line_table_sp.get() == NULL)
+ break;
+
+ if (ParseStatementTable(debug_line_data, &offset, line_table_sp.get()))
+ {
+ // Make sure we don't don't loop infinitely
+ if (offset <= debug_line_offset)
+ break;
+ //DEBUG_PRINTF("m_lineTableMap[0x%8.8x] = line_table_sp\n", debug_line_offset);
+ m_lineTableMap[debug_line_offset] = line_table_sp;
+ line_table_sp.reset(new LineTable);
+ }
+ else
+ ++offset; // Try next byte in line table
+ }
+}
+
+void
+DWARFDebugLine::ParseIfNeeded(const DataExtractor& debug_line_data)
+{
+ if (m_lineTableMap.empty())
+ Parse(debug_line_data);
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::GetLineTable
+//----------------------------------------------------------------------
+DWARFDebugLine::LineTable::shared_ptr
+DWARFDebugLine::GetLineTable(const dw_offset_t offset) const
+{
+ DWARFDebugLine::LineTable::shared_ptr line_table_shared_ptr;
+ LineTableConstIter pos = m_lineTableMap.find(offset);
+ if (pos != m_lineTableMap.end())
+ line_table_shared_ptr = pos->second;
+ return line_table_shared_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// DumpStateToFile
+//----------------------------------------------------------------------
+static void
+DumpStateToFile (dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ Log *log = (Log *)userData;
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // If the row is zero we are being called with the prologue only
+ state.prologue->Dump (log);
+ log->PutCString ("Address Line Column File");
+ log->PutCString ("------------------ ------ ------ ------");
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table
+ }
+ else
+ {
+ log->Printf( "0x%16.16llx %6u %6u %6u%s\n", state.address, state.line, state.column, state.file, state.end_sequence ? " END" : "");
+ }
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::DumpLineTableRows
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::DumpLineTableRows(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset)
+{
+ const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data();
+
+ if (debug_line_offset == DW_INVALID_OFFSET)
+ {
+ // Dump line table to a single file only
+ debug_line_offset = 0;
+ while (debug_line_data.ValidOffset(debug_line_offset))
+ debug_line_offset = DumpStatementTable (log, debug_line_data, debug_line_offset);
+ }
+ else
+ {
+ // Dump line table to a single file only
+ DumpStatementTable (log, debug_line_data, debug_line_offset);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::DumpStatementTable
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugLine::DumpStatementTable(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset)
+{
+ if (debug_line_data.ValidOffset(debug_line_offset))
+ {
+ uint32_t offset = debug_line_offset;
+ log->Printf( "----------------------------------------------------------------------\n"
+ "debug_line[0x%8.8x]\n"
+ "----------------------------------------------------------------------\n", debug_line_offset);
+
+ if (ParseStatementTable(debug_line_data, &offset, DumpStateToFile, log))
+ return offset;
+ else
+ return debug_line_offset + 1; // Skip to next byte in .debug_line section
+ }
+
+ return DW_INVALID_OFFSET;
+}
+
+
+//----------------------------------------------------------------------
+// DumpOpcodes
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::DumpOpcodes(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset, uint32_t dump_flags)
+{
+ const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data();
+
+ if (debug_line_data.GetByteSize() == 0)
+ {
+ log->Printf( "< EMPTY >\n");
+ return false;
+ }
+
+ if (debug_line_offset == DW_INVALID_OFFSET)
+ {
+ // Dump line table to a single file only
+ debug_line_offset = 0;
+ while (debug_line_data.ValidOffset(debug_line_offset))
+ debug_line_offset = DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags);
+ }
+ else
+ {
+ // Dump line table to a single file only
+ DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DumpStatementOpcodes
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugLine::DumpStatementOpcodes(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset, uint32_t flags)
+{
+ uint32_t offset = debug_line_offset;
+ if (debug_line_data.ValidOffset(offset))
+ {
+ Prologue prologue;
+
+ if (ParsePrologue(debug_line_data, &offset, &prologue))
+ {
+ log->PutCString ("----------------------------------------------------------------------");
+ log->Printf ("debug_line[0x%8.8x]", debug_line_offset);
+ log->PutCString ("----------------------------------------------------------------------\n");
+ prologue.Dump (log);
+ }
+ else
+ {
+ offset = debug_line_offset;
+ log->Printf( "0x%8.8x: skipping pad byte %2.2x", offset, debug_line_data.GetU8(&offset));
+ return offset;
+ }
+
+ Row row(prologue.default_is_stmt);
+ const dw_offset_t end_offset = debug_line_offset + prologue.total_length + sizeof(prologue.total_length);
+
+ assert(debug_line_data.ValidOffset(end_offset-1));
+
+ while (offset < end_offset)
+ {
+ const uint32_t op_offset = offset;
+ uint8_t opcode = debug_line_data.GetU8(&offset);
+ switch (opcode)
+ {
+ case 0: // Extended Opcodes always start with a zero opcode followed by
+ { // a uleb128 length so you can skip ones you don't know about
+
+ dw_offset_t ext_offset = offset;
+ dw_uleb128_t len = debug_line_data.GetULEB128(&offset);
+ dw_offset_t arg_size = len - (offset - ext_offset);
+ uint8_t sub_opcode = debug_line_data.GetU8(&offset);
+// if (verbose)
+// log->Printf( "Extended: <%u> %2.2x ", len, sub_opcode);
+
+ switch (sub_opcode)
+ {
+ case DW_LNE_end_sequence :
+ log->Printf( "0x%8.8x: DW_LNE_end_sequence", op_offset);
+ row.Dump(log);
+ row.Reset(prologue.default_is_stmt);
+ break;
+
+ case DW_LNE_set_address :
+ {
+ row.address = debug_line_data.GetMaxU64(&offset, arg_size);
+ log->Printf( "0x%8.8x: DW_LNE_set_address (0x%llx)", op_offset, row.address);
+ }
+ break;
+
+ case DW_LNE_define_file:
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = debug_line_data.GetCStr(&offset);
+ fileEntry.dir_idx = debug_line_data.GetULEB128(&offset);
+ fileEntry.mod_time = debug_line_data.GetULEB128(&offset);
+ fileEntry.length = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNE_define_file('%s', dir=%i, mod_time=0x%8.8x, length=%i )",
+ op_offset,
+ fileEntry.name.c_str(),
+ fileEntry.dir_idx,
+ fileEntry.mod_time,
+ fileEntry.length);
+ prologue.file_names.push_back(fileEntry);
+ }
+ break;
+
+ default:
+ log->Printf( "0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode);
+ // Length doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that below
+ offset += arg_size;
+ break;
+ }
+ }
+ break;
+
+ // Standard Opcodes
+ case DW_LNS_copy:
+ log->Printf( "0x%8.8x: DW_LNS_copy", op_offset);
+ row.Dump (log);
+ break;
+
+ case DW_LNS_advance_pc:
+ {
+ dw_uleb128_t addr_offset_n = debug_line_data.GetULEB128(&offset);
+ dw_uleb128_t addr_offset = addr_offset_n * prologue.min_inst_length;
+ log->Printf( "0x%8.8x: DW_LNS_advance_pc (0x%llx)", op_offset, addr_offset);
+ row.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_advance_line:
+ {
+ dw_sleb128_t line_offset = debug_line_data.GetSLEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_advance_line (%i)", op_offset, line_offset);
+ row.line += line_offset;
+ }
+ break;
+
+ case DW_LNS_set_file:
+ row.file = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_file (%u)", op_offset, row.file);
+ break;
+
+ case DW_LNS_set_column:
+ row.column = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_column (%u)", op_offset, row.column);
+ break;
+
+ case DW_LNS_negate_stmt:
+ row.is_stmt = !row.is_stmt;
+ log->Printf( "0x%8.8x: DW_LNS_negate_stmt", op_offset);
+ break;
+
+ case DW_LNS_set_basic_block:
+ row.basic_block = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_basic_block", op_offset);
+ break;
+
+ case DW_LNS_const_add_pc:
+ {
+ uint8_t adjust_opcode = 255 - prologue.opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length;
+ log->Printf( "0x%8.8x: DW_LNS_const_add_pc (0x%8.8llx)", op_offset, addr_offset);
+ row.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ {
+ uint16_t pc_offset = debug_line_data.GetU16(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_fixed_advance_pc (0x%4.4x)", op_offset, pc_offset);
+ row.address += pc_offset;
+ }
+ break;
+
+ case DW_LNS_set_prologue_end:
+ row.prologue_end = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_prologue_end", op_offset);
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ row.epilogue_begin = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_epilogue_begin", op_offset);
+ break;
+
+ case DW_LNS_set_isa:
+ row.isa = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_isa (%u)", op_offset, row.isa);
+ break;
+
+ // Special Opcodes
+ default:
+ if (opcode < prologue.opcode_base)
+ {
+ // We have an opcode that this parser doesn't know about, skip
+ // the number of ULEB128 numbers that is says to skip in the
+ // prologue's standard_opcode_lengths array
+ uint8_t n = prologue.standard_opcode_lengths[opcode-1];
+ log->Printf( "0x%8.8x: Special : Unknown skipping %u ULEB128 values.", op_offset, n);
+ while (n > 0)
+ {
+ debug_line_data.GetULEB128(&offset);
+ --n;
+ }
+ }
+ else
+ {
+ uint8_t adjust_opcode = opcode - prologue.opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length;
+ int32_t line_offset = prologue.line_base + (adjust_opcode % prologue.line_range);
+ log->Printf("0x%8.8x: address += 0x%llx, line += %i\n", op_offset, (uint64_t)addr_offset, line_offset);
+ row.address += addr_offset;
+ row.line += line_offset;
+ row.Dump (log);
+ }
+ break;
+ }
+ }
+ return end_offset;
+ }
+ return DW_INVALID_OFFSET;
+}
+
+
+
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parse the entire line table contents calling callback each time a
+// new prologue is parsed and every time a new row is to be added to
+// the line table.
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Parse(const DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData)
+{
+ uint32_t offset = 0;
+ if (debug_line_data.ValidOffset(offset))
+ {
+ if (!ParseStatementTable(debug_line_data, &offset, callback, userData))
+ ++offset; // Skip to next byte in .debug_line section
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::ParsePrologue
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParsePrologue(const DataExtractor& debug_line_data, dw_offset_t* offset_ptr, Prologue* prologue)
+{
+// const uint32_t prologue_offset = *offset_ptr;
+
+ //DEBUG_PRINTF("0x%8.8x: ParsePrologue()\n", *offset_ptr);
+
+ prologue->Clear();
+ uint32_t i;
+ const char * s;
+ prologue->total_length = debug_line_data.GetU32(offset_ptr);
+ prologue->version = debug_line_data.GetU16(offset_ptr);
+ if (prologue->version != 2)
+ return false;
+
+ prologue->prologue_length = debug_line_data.GetU32(offset_ptr);
+ const dw_offset_t end_prologue_offset = prologue->prologue_length + *offset_ptr;
+ prologue->min_inst_length = debug_line_data.GetU8(offset_ptr);
+ prologue->default_is_stmt = debug_line_data.GetU8(offset_ptr);
+ prologue->line_base = debug_line_data.GetU8(offset_ptr);
+ prologue->line_range = debug_line_data.GetU8(offset_ptr);
+ prologue->opcode_base = debug_line_data.GetU8(offset_ptr);
+
+ prologue->standard_opcode_lengths.reserve(prologue->opcode_base-1);
+
+ for (i=1; i<prologue->opcode_base; ++i)
+ {
+ uint8_t op_len = debug_line_data.GetU8(offset_ptr);
+ prologue->standard_opcode_lengths.push_back(op_len);
+ }
+
+ while (*offset_ptr < end_prologue_offset)
+ {
+ s = debug_line_data.GetCStr(offset_ptr);
+ if (s && s[0])
+ prologue->include_directories.push_back(s);
+ else
+ break;
+ }
+
+ while (*offset_ptr < end_prologue_offset)
+ {
+ const char* name = debug_line_data.GetCStr( offset_ptr );
+ if (name && name[0])
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = name;
+ fileEntry.dir_idx = debug_line_data.GetULEB128( offset_ptr );
+ fileEntry.mod_time = debug_line_data.GetULEB128( offset_ptr );
+ fileEntry.length = debug_line_data.GetULEB128( offset_ptr );
+ prologue->file_names.push_back(fileEntry);
+ }
+ else
+ break;
+ }
+
+ assert(*offset_ptr == end_prologue_offset);
+ return end_prologue_offset;
+}
+
+bool
+DWARFDebugLine::ParseSupportFiles(const DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, FileSpecList &support_files)
+{
+ uint32_t offset = stmt_list + 4; // Skip the total length
+ const char * s;
+ uint32_t version = debug_line_data.GetU16(&offset);
+ if (version != 2)
+ return false;
+
+ const dw_offset_t end_prologue_offset = debug_line_data.GetU32(&offset) + offset;
+ // Skip instruction length, default is stmt, line base, line range and
+ // opcode base, and all opcode lengths
+ offset += 4;
+ const uint8_t opcode_base = debug_line_data.GetU8(&offset);
+ offset += opcode_base - 1;
+ std::vector<std::string> include_directories;
+ include_directories.push_back(""); // Directory at index zero doesn't exist
+ while (offset < end_prologue_offset)
+ {
+ s = debug_line_data.GetCStr(&offset);
+ if (s && s[0])
+ include_directories.push_back(s);
+ else
+ break;
+ }
+ std::string fullpath;
+ while (offset < end_prologue_offset)
+ {
+ const char* path = debug_line_data.GetCStr( &offset );
+ if (path && path[0])
+ {
+ uint32_t dir_idx = debug_line_data.GetULEB128( &offset );
+ debug_line_data.Skip_LEB128(&offset); // Skip mod_time
+ debug_line_data.Skip_LEB128(&offset); // Skip length
+
+ if (path[0] == '/')
+ {
+ // The path starts with a directory delimiter, so we are done.
+ fullpath = path;
+ }
+ else
+ {
+ if (dir_idx > 0 && dir_idx < include_directories.size())
+ {
+ if (cu_comp_dir && include_directories[dir_idx][0] != '/')
+ {
+ fullpath = cu_comp_dir;
+
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ fullpath += include_directories[dir_idx];
+
+ }
+ else
+ fullpath = include_directories[dir_idx];
+ }
+ else if (cu_comp_dir && cu_comp_dir[0])
+ {
+ fullpath = cu_comp_dir;
+ }
+
+ if (!fullpath.empty())
+ {
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ }
+ fullpath += path;
+ }
+ FileSpec file_spec(fullpath.c_str());
+ support_files.Append(file_spec);
+ }
+ }
+
+ assert(offset == end_prologue_offset);
+ return end_prologue_offset;
+}
+
+//----------------------------------------------------------------------
+// ParseStatementTable
+//
+// Parse a single line table (prologue and all rows) and call the
+// callback function once for the prologue (row in state will be zero)
+// and each time a row is to be added to the line table.
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParseStatementTable
+(
+ const DataExtractor& debug_line_data,
+ dw_offset_t* offset_ptr,
+ DWARFDebugLine::State::Callback callback,
+ void* userData
+)
+{
+ Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_LINE);
+ Prologue::shared_ptr prologue(new Prologue());
+
+
+ const dw_offset_t debug_line_offset = *offset_ptr;
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugLine::ParseStatementTable (.debug_line[0x%8.8x])",
+ debug_line_offset);
+
+ if (!ParsePrologue(debug_line_data, offset_ptr, prologue.get()))
+ {
+ if (log)
+ log->Error ("failed to parse DWARF line table prologue");
+ // Restore our offset and return false to indicate failure!
+ *offset_ptr = debug_line_offset;
+ return false;
+ }
+
+ if (log)
+ prologue->Dump (log);
+
+ const dw_offset_t end_offset = debug_line_offset + prologue->total_length + sizeof(prologue->total_length);
+
+ assert(debug_line_data.ValidOffset(end_offset-1));
+
+ State state(prologue, log, callback, userData);
+
+ while (*offset_ptr < end_offset)
+ {
+ //DEBUG_PRINTF("0x%8.8x: ", *offset_ptr);
+ uint8_t opcode = debug_line_data.GetU8(offset_ptr);
+
+ if (opcode == 0)
+ {
+ // Extended Opcodes always start with a zero opcode followed by
+ // a uleb128 length so you can skip ones you don't know about
+ dw_offset_t ext_offset = *offset_ptr;
+ dw_uleb128_t len = debug_line_data.GetULEB128(offset_ptr);
+ dw_offset_t arg_size = len - (*offset_ptr - ext_offset);
+
+ //DEBUG_PRINTF("Extended: <%2u> ", len);
+ uint8_t sub_opcode = debug_line_data.GetU8(offset_ptr);
+ switch (sub_opcode)
+ {
+ case DW_LNE_end_sequence:
+ // Set the end_sequence register of the state machine to true and
+ // append a row to the matrix using the current values of the
+ // state-machine registers. Then reset the registers to the initial
+ // values specified above. Every statement program sequence must end
+ // with a DW_LNE_end_sequence instruction which creates a row whose
+ // address is that of the byte after the last target machine instruction
+ // of the sequence.
+ state.end_sequence = true;
+ state.AppendRowToMatrix(*offset_ptr);
+ state.Reset();
+ break;
+
+ case DW_LNE_set_address:
+ // Takes a single relocatable address as an operand. The size of the
+ // operand is the size appropriate to hold an address on the target
+ // machine. Set the address register to the value given by the
+ // relocatable address. All of the other statement program opcodes
+ // that affect the address register add a delta to it. This instruction
+ // stores a relocatable value into it instead.
+ state.address = debug_line_data.GetAddress(offset_ptr);
+ break;
+
+ case DW_LNE_define_file:
+ // Takes 4 arguments. The first is a null terminated string containing
+ // a source file name. The second is an unsigned LEB128 number representing
+ // the directory index of the directory in which the file was found. The
+ // third is an unsigned LEB128 number representing the time of last
+ // modification of the file. The fourth is an unsigned LEB128 number
+ // representing the length in bytes of the file. The time and length
+ // fields may contain LEB128(0) if the information is not available.
+ //
+ // The directory index represents an entry in the include_directories
+ // section of the statement program prologue. The index is LEB128(0)
+ // if the file was found in the current directory of the compilation,
+ // LEB128(1) if it was found in the first directory in the
+ // include_directories section, and so on. The directory index is
+ // ignored for file names that represent full path names.
+ //
+ // The files are numbered, starting at 1, in the order in which they
+ // appear; the names in the prologue come before names defined by
+ // the DW_LNE_define_file instruction. These numbers are used in the
+ // the file register of the state machine.
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = debug_line_data.GetCStr(offset_ptr);
+ fileEntry.dir_idx = debug_line_data.GetULEB128(offset_ptr);
+ fileEntry.mod_time = debug_line_data.GetULEB128(offset_ptr);
+ fileEntry.length = debug_line_data.GetULEB128(offset_ptr);
+ state.prologue->file_names.push_back(fileEntry);
+ }
+ break;
+
+ default:
+ // Length doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that below
+ (*offset_ptr) += arg_size;
+ break;
+ }
+ }
+ else if (opcode < prologue->opcode_base)
+ {
+ switch (opcode)
+ {
+ // Standard Opcodes
+ case DW_LNS_copy:
+ // Takes no arguments. Append a row to the matrix using the
+ // current values of the state-machine registers. Then set
+ // the basic_block register to false.
+ state.AppendRowToMatrix(*offset_ptr);
+ break;
+
+ case DW_LNS_advance_pc:
+ // Takes a single unsigned LEB128 operand, multiplies it by the
+ // min_inst_length field of the prologue, and adds the
+ // result to the address register of the state machine.
+ state.address += debug_line_data.GetULEB128(offset_ptr) * prologue->min_inst_length;
+ break;
+
+ case DW_LNS_advance_line:
+ // Takes a single signed LEB128 operand and adds that value to
+ // the line register of the state machine.
+ state.line += debug_line_data.GetSLEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_file:
+ // Takes a single unsigned LEB128 operand and stores it in the file
+ // register of the state machine.
+ state.file = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_column:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ state.column = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_negate_stmt:
+ // Takes no arguments. Set the is_stmt register of the state
+ // machine to the logical negation of its current value.
+ state.is_stmt = !state.is_stmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ state.basic_block = true;
+ break;
+
+ case DW_LNS_const_add_pc:
+ // Takes no arguments. Add to the address register of the state
+ // machine the address increment value corresponding to special
+ // opcode 255. The motivation for DW_LNS_const_add_pc is this:
+ // when the statement program needs to advance the address by a
+ // small amount, it can use a single special opcode, which occupies
+ // a single byte. When it needs to advance the address by up to
+ // twice the range of the last special opcode, it can use
+ // DW_LNS_const_add_pc followed by a special opcode, for a total
+ // of two bytes. Only if it needs to advance the address by more
+ // than twice that range will it need to use both DW_LNS_advance_pc
+ // and a special opcode, requiring three or more bytes.
+ {
+ uint8_t adjust_opcode = 255 - prologue->opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length;
+ state.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ // Takes a single uhalf operand. Add to the address register of
+ // the state machine the value of the (unencoded) operand. This
+ // is the only extended opcode that takes an argument that is not
+ // a variable length number. The motivation for DW_LNS_fixed_advance_pc
+ // is this: existing assemblers cannot emit DW_LNS_advance_pc or
+ // special opcodes because they cannot encode LEB128 numbers or
+ // judge when the computation of a special opcode overflows and
+ // requires the use of DW_LNS_advance_pc. Such assemblers, however,
+ // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+ state.address += debug_line_data.GetU16(offset_ptr);
+ break;
+
+ case DW_LNS_set_prologue_end:
+ // Takes no arguments. Set the prologue_end register of the
+ // state machine to true
+ state.prologue_end = true;
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ state.epilogue_begin = true;
+ break;
+
+ case DW_LNS_set_isa:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ state.isa = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ default:
+ // Handle any unknown standard opcodes here. We know the lengths
+ // of such opcodes because they are specified in the prologue
+ // as a multiple of LEB128 operands for each opcode.
+ {
+ uint8_t i;
+ assert (opcode - 1 < prologue->standard_opcode_lengths.size());
+ const uint8_t opcode_length = prologue->standard_opcode_lengths[opcode - 1];
+ for (i=0; i<opcode_length; ++i)
+ debug_line_data.Skip_LEB128(offset_ptr);
+ }
+ break;
+ }
+ }
+ else
+ {
+ // Special Opcodes
+
+ // A special opcode value is chosen based on the amount that needs
+ // to be added to the line and address registers. The maximum line
+ // increment for a special opcode is the value of the line_base
+ // field in the header, plus the value of the line_range field,
+ // minus 1 (line base + line range - 1). If the desired line
+ // increment is greater than the maximum line increment, a standard
+ // opcode must be used instead of a special opcode. The “address
+ // advance” is calculated by dividing the desired address increment
+ // by the minimum_instruction_length field from the header. The
+ // special opcode is then calculated using the following formula:
+ //
+ // opcode = (desired line increment - line_base) + (line_range * address advance) + opcode_base
+ //
+ // If the resulting opcode is greater than 255, a standard opcode
+ // must be used instead.
+ //
+ // To decode a special opcode, subtract the opcode_base from the
+ // opcode itself to give the adjusted opcode. The amount to
+ // increment the address register is the result of the adjusted
+ // opcode divided by the line_range multiplied by the
+ // minimum_instruction_length field from the header. That is:
+ //
+ // address increment = (adjusted opcode / line_range) * minimim_instruction_length
+ //
+ // The amount to increment the line register is the line_base plus
+ // the result of the adjusted opcode modulo the line_range. That is:
+ //
+ // line increment = line_base + (adjusted opcode % line_range)
+
+ uint8_t adjust_opcode = opcode - prologue->opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length;
+ int32_t line_offset = prologue->line_base + (adjust_opcode % prologue->line_range);
+ state.line += line_offset;
+ state.address += addr_offset;
+ state.AppendRowToMatrix(*offset_ptr);
+ }
+ }
+
+ state.Finalize( *offset_ptr );
+
+ return end_offset;
+}
+
+
+//----------------------------------------------------------------------
+// ParseStatementTableCallback
+//----------------------------------------------------------------------
+static void
+ParseStatementTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ DWARFDebugLine::LineTable* line_table = (DWARFDebugLine::LineTable*)userData;
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // Just started parsing the line table, so lets keep a reference to
+ // the prologue using the supplied shared pointer
+ line_table->prologue = state.prologue;
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table, nothing to do for the cleanup
+ }
+ else
+ {
+ // We have a new row, lets append it
+ line_table->AppendRow(state);
+ }
+}
+
+//----------------------------------------------------------------------
+// ParseStatementTable
+//
+// Parse a line table at offset and populate the LineTable class with
+// the prologue and all rows.
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParseStatementTable(const DataExtractor& debug_line_data, uint32_t* offset_ptr, LineTable* line_table)
+{
+ return ParseStatementTable(debug_line_data, offset_ptr, ParseStatementTableCallback, line_table);
+}
+
+
+inline bool
+DWARFDebugLine::Prologue::IsValid() const
+{
+ return SymbolFileDWARF::SupportedVersion(version);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Prologue::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Prologue::Dump(Log *log)
+{
+ uint32_t i;
+
+ log->Printf( "Line table prologue:");
+ log->Printf( " total_length: 0x%8.8x", total_length);
+ log->Printf( " version: %u", version);
+ log->Printf( "prologue_length: 0x%8.8x", prologue_length);
+ log->Printf( "min_inst_length: %u", min_inst_length);
+ log->Printf( "default_is_stmt: %u", default_is_stmt);
+ log->Printf( " line_base: %i", line_base);
+ log->Printf( " line_range: %u", line_range);
+ log->Printf( " opcode_base: %u", opcode_base);
+
+ for (i=0; i<standard_opcode_lengths.size(); ++i)
+ {
+ log->Printf( "standard_opcode_lengths[%s] = %u", DW_LNS_value_to_name(i+1), standard_opcode_lengths[i]);
+ }
+
+ if (!include_directories.empty())
+ {
+ for (i=0; i<include_directories.size(); ++i)
+ {
+ log->Printf( "include_directories[%3u] = '%s'", i+1, include_directories[i].c_str());
+ }
+ }
+
+ if (!file_names.empty())
+ {
+ log->PutCString (" Dir Mod Time File Len File Name");
+ log->PutCString (" ---- ---------- ---------- ---------------------------");
+ for (i=0; i<file_names.size(); ++i)
+ {
+ const FileNameEntry& fileEntry = file_names[i];
+ log->Printf ("file_names[%3u] %4u 0x%8.8x 0x%8.8x %s",
+ i+1,
+ fileEntry.dir_idx,
+ fileEntry.mod_time,
+ fileEntry.length,
+ fileEntry.name.c_str());
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::ParsePrologue::Append
+//
+// Append the contents of the prologue to the binary stream buffer
+//----------------------------------------------------------------------
+//void
+//DWARFDebugLine::Prologue::Append(BinaryStreamBuf& buff) const
+//{
+// uint32_t i;
+//
+// buff.Append32(total_length);
+// buff.Append16(version);
+// buff.Append32(prologue_length);
+// buff.Append8(min_inst_length);
+// buff.Append8(default_is_stmt);
+// buff.Append8(line_base);
+// buff.Append8(line_range);
+// buff.Append8(opcode_base);
+//
+// for (i=0; i<standard_opcode_lengths.size(); ++i)
+// buff.Append8(standard_opcode_lengths[i]);
+//
+// for (i=0; i<include_directories.size(); ++i)
+// buff.AppendCStr(include_directories[i].c_str());
+// buff.Append8(0); // Terminate the include directory section with empty string
+//
+// for (i=0; i<file_names.size(); ++i)
+// {
+// buff.AppendCStr(file_names[i].name.c_str());
+// buff.Append32_as_ULEB128(file_names[i].dir_idx);
+// buff.Append32_as_ULEB128(file_names[i].mod_time);
+// buff.Append32_as_ULEB128(file_names[i].length);
+// }
+// buff.Append8(0); // Terminate the file names section with empty string
+//}
+
+
+bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, std::string& path, std::string& directory) const
+{
+ uint32_t idx = file_idx - 1; // File indexes are 1 based...
+ if (idx < file_names.size())
+ {
+ path = file_names[idx].name;
+ uint32_t dir_idx = file_names[idx].dir_idx - 1;
+ if (dir_idx < include_directories.size())
+ directory = include_directories[dir_idx];
+ else
+ directory.clear();
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::LineTable::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::LineTable::Dump(Log *log) const
+{
+ if (prologue.get())
+ prologue->Dump (log);
+
+ if (!rows.empty())
+ {
+ log->PutCString ("Address Line Column File ISA Flags");
+ log->PutCString ("------------------ ------ ------ ------ --- -------------");
+ Row::const_iterator pos = rows.begin();
+ Row::const_iterator end = rows.end();
+ while (pos != end)
+ {
+ (*pos).Dump (log);
+ ++pos;
+ }
+ }
+}
+
+
+void
+DWARFDebugLine::LineTable::AppendRow(const DWARFDebugLine::Row& state)
+{
+ rows.push_back(state);
+}
+
+
+
+//----------------------------------------------------------------------
+// Compare function for the binary search in DWARFDebugLine::LineTable::LookupAddress()
+//----------------------------------------------------------------------
+static bool FindMatchingAddress (const DWARFDebugLine::Row& row1, const DWARFDebugLine::Row& row2)
+{
+ return row1.address < row2.address;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::LineTable::LookupAddress
+//----------------------------------------------------------------------
+uint32_t
+DWARFDebugLine::LineTable::LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const
+{
+ uint32_t index = UINT_MAX;
+ if (!rows.empty())
+ {
+ // Use the lower_bound algorithm to perform a binary search since we know
+ // that our line table data is ordered by address.
+ DWARFDebugLine::Row row;
+ row.address = address;
+ Row::const_iterator begin_pos = rows.begin();
+ Row::const_iterator end_pos = rows.end();
+ Row::const_iterator pos = lower_bound(begin_pos, end_pos, row, FindMatchingAddress);
+ if (pos == end_pos)
+ {
+ if (address < cu_high_pc)
+ return rows.size()-1;
+ }
+ else
+ {
+ // Rely on fact that we are using a std::vector and we can do
+ // pointer arithmetic to find the row index (which will be one less
+ // that what we found since it will find the first position after
+ // the current address) since std::vector iterators are just
+ // pointers to the container type.
+ index = pos - begin_pos;
+ if (pos->address > address)
+ {
+ if (index > 0)
+ --index;
+ else
+ index = UINT_MAX;
+ }
+ }
+ }
+ return index; // Failed to find address
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Row
+//----------------------------------------------------------------------
+DWARFDebugLine::Row::Row(bool default_is_stmt) :
+ address(0),
+ line(1),
+ column(0),
+ file(1),
+ is_stmt(default_is_stmt),
+ basic_block(false),
+ end_sequence(false),
+ prologue_end(false),
+ epilogue_begin(false),
+ isa(0)
+{
+}
+
+//----------------------------------------------------------------------
+// Called after a row is appended to the matrix
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::PostAppend()
+{
+ basic_block = false;
+ prologue_end = false;
+ epilogue_begin = false;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Reset
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::Reset(bool default_is_stmt)
+{
+ address = 0;
+ line = 1;
+ column = 0;
+ file = 1;
+ is_stmt = default_is_stmt;
+ basic_block = false;
+ end_sequence = false;
+ prologue_end = false;
+ epilogue_begin = false;
+ isa = 0;
+}
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::Dump(Log *log) const
+{
+ log->Printf( "0x%16.16llx %6u %6u %6u %3u %s%s%s%s%s",
+ address,
+ line,
+ column,
+ file,
+ isa,
+ is_stmt ? " is_stmt" : "",
+ basic_block ? " basic_block" : "",
+ prologue_end ? " prologue_end" : "",
+ epilogue_begin ? " epilogue_begin" : "",
+ end_sequence ? " end_sequence" : "");
+}
+
+//----------------------------------------------------------------------
+// Compare function LineTable structures
+//----------------------------------------------------------------------
+static bool AddressLessThan (const DWARFDebugLine::Row& a, const DWARFDebugLine::Row& b)
+{
+ return a.address < b.address;
+}
+
+
+
+// Insert a row at the correct address if the addresses can be out of
+// order which can only happen when we are linking a line table that
+// may have had it's contents rearranged.
+void
+DWARFDebugLine::Row::Insert(Row::collection& state_coll, const Row& state)
+{
+ // If we don't have anything yet, or if the address of the last state in our
+ // line table is less than the current one, just append the current state
+ if (state_coll.empty() || AddressLessThan(state_coll.back(), state))
+ {
+ state_coll.push_back(state);
+ }
+ else
+ {
+ // Do a binary search for the correct entry
+ pair<Row::iterator, Row::iterator> range(equal_range(state_coll.begin(), state_coll.end(), state, AddressLessThan));
+
+ // If the addresses are equal, we can safely replace the previous entry
+ // with the current one if the one it is replacing is an end_sequence entry.
+ // We currently always place an extra end sequence when ever we exit a valid
+ // address range for a function in case the functions get rearranged by
+ // optmimizations or by order specifications. These extra end sequences will
+ // disappear by getting replaced with valid consecutive entries within a
+ // compile unit if there are no gaps.
+ if (range.first == range.second)
+ {
+ state_coll.insert(range.first, state);
+ }
+ else
+ {
+ if ((distance(range.first, range.second) == 1) && range.first->end_sequence == true)
+ {
+ *range.first = state;
+ }
+ else
+ {
+ state_coll.insert(range.second, state);
+ }
+ }
+ }
+}
+
+void
+DWARFDebugLine::Row::Dump(Log *log, const Row::collection& state_coll)
+{
+ std::for_each (state_coll.begin(), state_coll.end(), bind2nd(std::mem_fun_ref(&Row::Dump),log));
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::State
+//----------------------------------------------------------------------
+DWARFDebugLine::State::State(Prologue::shared_ptr& p, Log *l, DWARFDebugLine::State::Callback cb, void* userData) :
+ Row (p->default_is_stmt),
+ prologue (p),
+ log (l),
+ callback (cb),
+ callbackUserData (userData),
+ row (StartParsingLineTable)
+{
+ // Call the callback with the initial row state of zero for the prologue
+ if (callback)
+ callback(0, *this, callbackUserData);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::Reset
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::Reset()
+{
+ Row::Reset(prologue->default_is_stmt);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::AppendRowToMatrix
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset)
+{
+ // Each time we are to add an entry into the line table matrix
+ // call the callback funtion so that someone can do something with
+ // the current state of the state machine (like build a line table
+ // or dump the line table!)
+ if (log)
+ {
+ if (row == 0)
+ {
+ log->PutCString ("Address Line Column File ISA Flags");
+ log->PutCString ("------------------ ------ ------ ------ --- -------------");
+ }
+ Dump (log);
+ }
+
+ ++row; // Increase the row number before we call our callback for a real row
+ if (callback)
+ callback(offset, *this, callbackUserData);
+ PostAppend();
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::Finalize
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::Finalize(dw_offset_t offset)
+{
+ // Call the callback with a special row state when we are done parsing a
+ // line table
+ row = DoneParsingLineTable;
+ if (callback)
+ callback(offset, *this, callbackUserData);
+}
+
+//void
+//DWARFDebugLine::AppendLineTableData
+//(
+// const DWARFDebugLine::Prologue* prologue,
+// const DWARFDebugLine::Row::collection& state_coll,
+// const uint32_t addr_size,
+// BinaryStreamBuf &debug_line_data
+//)
+//{
+// if (state_coll.empty())
+// {
+// // We have no entries, just make an empty line table
+// debug_line_data.Append8(0);
+// debug_line_data.Append8(1);
+// debug_line_data.Append8(DW_LNE_end_sequence);
+// }
+// else
+// {
+// DWARFDebugLine::Row::const_iterator pos;
+// Row::const_iterator end = state_coll.end();
+// bool default_is_stmt = prologue->default_is_stmt;
+// const DWARFDebugLine::Row reset_state(default_is_stmt);
+// const DWARFDebugLine::Row* prev_state = &reset_state;
+// const int32_t max_line_increment_for_special_opcode = prologue->MaxLineIncrementForSpecialOpcode();
+// for (pos = state_coll.begin(); pos != end; ++pos)
+// {
+// const DWARFDebugLine::Row& curr_state = *pos;
+// int32_t line_increment = 0;
+// dw_addr_t addr_offset = curr_state.address - prev_state->address;
+// dw_addr_t addr_advance = (addr_offset) / prologue->min_inst_length;
+// line_increment = (int32_t)(curr_state.line - prev_state->line);
+//
+// // If our previous state was the reset state, then let's emit the
+// // address to keep GDB's DWARF parser happy. If we don't start each
+// // sequence with a DW_LNE_set_address opcode, the line table won't
+// // get slid properly in GDB.
+//
+// if (prev_state == &reset_state)
+// {
+// debug_line_data.Append8(0); // Extended opcode
+// debug_line_data.Append32_as_ULEB128(addr_size + 1); // Length of opcode bytes
+// debug_line_data.Append8(DW_LNE_set_address);
+// debug_line_data.AppendMax64(curr_state.address, addr_size);
+// addr_advance = 0;
+// }
+//
+// if (prev_state->file != curr_state.file)
+// {
+// debug_line_data.Append8(DW_LNS_set_file);
+// debug_line_data.Append32_as_ULEB128(curr_state.file);
+// }
+//
+// if (prev_state->column != curr_state.column)
+// {
+// debug_line_data.Append8(DW_LNS_set_column);
+// debug_line_data.Append32_as_ULEB128(curr_state.column);
+// }
+//
+// // Don't do anything fancy if we are at the end of a sequence
+// // as we don't want to push any extra rows since the DW_LNE_end_sequence
+// // will push a row itself!
+// if (curr_state.end_sequence)
+// {
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Now push the end sequence on!
+// debug_line_data.Append8(0);
+// debug_line_data.Append8(1);
+// debug_line_data.Append8(DW_LNE_end_sequence);
+//
+// prev_state = &reset_state;
+// }
+// else
+// {
+// if (line_increment || addr_advance)
+// {
+// if (line_increment > max_line_increment_for_special_opcode)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// line_increment = 0;
+// }
+//
+// uint32_t special_opcode = (line_increment >= prologue->line_base) ? ((line_increment - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256;
+// if (special_opcode > 255)
+// {
+// // Both the address and line won't fit in one special opcode
+// // check to see if just the line advance will?
+// uint32_t special_opcode_line = ((line_increment >= prologue->line_base) && (line_increment != 0)) ?
+// ((line_increment - prologue->line_base) + prologue->opcode_base) : 256;
+//
+//
+// if (special_opcode_line > 255)
+// {
+// // Nope, the line advance won't fit by itself, check the address increment by itself
+// uint32_t special_opcode_addr = addr_advance ?
+// ((0 - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256;
+//
+// if (special_opcode_addr > 255)
+// {
+// // Neither the address nor the line will fit in a
+// // special opcode, we must manually enter both then
+// // do a DW_LNS_copy to push a row (special opcode
+// // automatically imply a new row is pushed)
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Now push a row onto the line table manually
+// debug_line_data.Append8(DW_LNS_copy);
+//
+// }
+// else
+// {
+// // The address increment alone will fit into a special opcode
+// // so modify our line change, then issue a special opcode
+// // for the address increment and it will push a row into the
+// // line table
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode_addr);
+// }
+// }
+// else
+// {
+// // The line change alone will fit into a special opcode
+// // so modify our address increment first, then issue a
+// // special opcode for the line change and it will push
+// // a row into the line table
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode_line);
+// }
+// }
+// else
+// {
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode);
+// }
+// }
+// prev_state = &curr_state;
+// }
+// }
+// }
+//}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
new file mode 100644
index 0000000..57b2f15
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
@@ -0,0 +1,225 @@
+//===-- DWARFDebugLine.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_DWARFDebugLine_h_
+#define liblldb_DWARFDebugLine_h_
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "lldb/lldb-private.h"
+
+#include "DWARFDefines.h"
+
+class SymbolFileDWARF;
+class DWARFDebugInfoEntry;
+
+//----------------------------------------------------------------------
+// DWARFDebugLine
+//----------------------------------------------------------------------
+class DWARFDebugLine
+{
+public:
+ //------------------------------------------------------------------
+ // FileNameEntry
+ //------------------------------------------------------------------
+ struct FileNameEntry
+ {
+ FileNameEntry() :
+ name(),
+ dir_idx(0),
+ mod_time(0),
+ length(0)
+ {
+ }
+
+ std::string name;
+ dw_sleb128_t dir_idx;
+ dw_sleb128_t mod_time;
+ dw_sleb128_t length;
+
+ };
+
+ //------------------------------------------------------------------
+ // Prologue
+ //------------------------------------------------------------------
+ struct Prologue
+ {
+
+ Prologue() :
+ total_length(0),
+ version(0),
+ prologue_length(0),
+ min_inst_length(0),
+ default_is_stmt(0),
+ line_base(0),
+ line_range(0),
+ opcode_base(0),
+ standard_opcode_lengths(),
+ include_directories(),
+ file_names()
+ {
+ }
+
+ typedef lldb::SharedPtr<Prologue>::Type shared_ptr;
+
+ uint32_t total_length; // The size in bytes of the statement information for this compilation unit (not including the total_length field itself).
+ uint16_t version; // Version identifier for the statement information format.
+ uint32_t prologue_length;// The number of bytes following the prologue_length field to the beginning of the first byte of the statement program itself.
+ uint8_t min_inst_length;// The size in bytes of the smallest target machine instruction. Statement program opcodes that alter the address register first multiply their operands by this value.
+ uint8_t default_is_stmt;// The initial value of theis_stmtregister.
+ int8_t line_base; // This parameter affects the meaning of the special opcodes. See below.
+ uint8_t line_range; // This parameter affects the meaning of the special opcodes. See below.
+ uint8_t opcode_base; // The number assigned to the first special opcode.
+ std::vector<uint8_t> standard_opcode_lengths;
+ std::vector<std::string> include_directories;
+ std::vector<FileNameEntry> file_names;
+
+ // Length of the prologue in bytes
+ uint32_t Length() const { return prologue_length + sizeof(total_length) + sizeof(version) + sizeof(prologue_length); }
+ // Length of the line table data in bytes (not including the prologue)
+ uint32_t StatementTableLength() const { return total_length + sizeof(total_length) - Length(); }
+ int32_t MaxLineIncrementForSpecialOpcode() const { return line_base + (int8_t)line_range - 1; };
+ bool IsValid() const;
+// void Append(BinaryStreamBuf& buff) const;
+ void Dump (lldb_private::Log *log);
+ void Clear()
+ {
+ total_length = version = prologue_length = min_inst_length = line_base = line_range = opcode_base = 0;
+ line_base = 0;
+ standard_opcode_lengths.clear();
+ include_directories.clear();
+ file_names.clear();
+ }
+ bool GetFile(uint32_t file_idx, std::string& file, std::string& dir) const;
+
+ };
+
+ // Standard .debug_line state machine structure
+ struct Row
+ {
+ typedef std::vector<Row> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ Row(bool default_is_stmt = false);
+ virtual ~Row() {}
+ void PostAppend ();
+ void Reset(bool default_is_stmt);
+ void Dump(lldb_private::Log *log) const;
+ static void Insert(Row::collection& state_coll, const Row& state);
+ static void Dump(lldb_private::Log *log, const Row::collection& state_coll);
+
+ dw_addr_t address; // The program-counter value corresponding to a machine instruction generated by the compiler.
+ uint32_t line; // An unsigned integer indicating a source line number. Lines are numbered beginning at 1. The compiler may emit the value 0 in cases where an instruction cannot be attributed to any source line.
+ uint16_t column; // An unsigned integer indicating a column number within a source line. Columns are numbered beginning at 1. The value 0 is reserved to indicate that a statement begins at the ‘‘left edge’’ of the line.
+ uint16_t file; // An unsigned integer indicating the identity of the source file corresponding to a machine instruction.
+ uint8_t is_stmt:1, // A boolean indicating that the current instruction is the beginning of a statement.
+ basic_block:1, // A boolean indicating that the current instruction is the beginning of a basic block.
+ end_sequence:1, // A boolean indicating that the current address is that of the first byte after the end of a sequence of target machine instructions.
+ prologue_end:1, // A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an entry breakpoint of a function.
+ epilogue_begin:1;// A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an exit breakpoint of a function.
+ uint32_t isa; // An unsigned integer whose value encodes the applicable instruction set architecture for the current instruction.
+ };
+
+
+ //------------------------------------------------------------------
+ // LineTable
+ //------------------------------------------------------------------
+ struct LineTable
+ {
+ typedef lldb::SharedPtr<LineTable>::Type shared_ptr;
+
+ LineTable() :
+ prologue(),
+ rows()
+ {
+ }
+
+ void AppendRow(const DWARFDebugLine::Row& state);
+ void Clear()
+ {
+ prologue.reset();
+ rows.clear();
+ }
+
+ uint32_t LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const;
+ void Dump(lldb_private::Log *log) const;
+
+ Prologue::shared_ptr prologue;
+ Row::collection rows;
+ };
+
+ //------------------------------------------------------------------
+ // State
+ //------------------------------------------------------------------
+ struct State : public Row
+ {
+ typedef void (*Callback)(dw_offset_t offset, const State& state, void* userData);
+
+ // Special row codes used when calling the callback
+ enum
+ {
+ StartParsingLineTable = 0,
+ DoneParsingLineTable = -1
+ };
+
+ State (Prologue::shared_ptr& prologue_sp,
+ lldb_private::Log *log,
+ Callback callback,
+ void* userData);
+
+ void
+ AppendRowToMatrix (dw_offset_t offset);
+
+ void
+ Finalize (dw_offset_t offset);
+
+ void
+ Reset ();
+
+ Prologue::shared_ptr prologue;
+ lldb_private::Log *log;
+ Callback callback; // Callback funcation that gets called each time an entry it to be added to the matrix
+ void* callbackUserData;
+ int row; // The row number that starts at zero for the prologue, and increases for each row added to the matrix
+ private:
+ DISALLOW_COPY_AND_ASSIGN (State);
+ };
+
+ static bool DumpOpcodes(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET, uint32_t dump_flags = 0); // If line_offset is invalid, dump everything
+ static bool DumpLineTableRows(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET); // If line_offset is invalid, dump everything
+ static bool ParseSupportFiles(const lldb_private::DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, lldb_private::FileSpecList &support_files);
+ static bool ParsePrologue(const lldb_private::DataExtractor& debug_line_data, dw_offset_t* offset_ptr, Prologue* prologue);
+ static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, dw_offset_t* offset_ptr, State::Callback callback, void* userData);
+ static dw_offset_t DumpStatementTable(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset);
+ static dw_offset_t DumpStatementOpcodes(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset, uint32_t flags);
+ static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, uint32_t* offset_ptr, LineTable* line_table);
+ static void Parse(const lldb_private::DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData);
+// static void AppendLineTableData(const DWARFDebugLine::Prologue* prologue, const DWARFDebugLine::Row::collection& state_coll, const uint32_t addr_size, BinaryStreamBuf &debug_line_data);
+
+ DWARFDebugLine() :
+ m_lineTableMap()
+ {
+ }
+
+ void Parse(const lldb_private::DataExtractor& debug_line_data);
+ void ParseIfNeeded(const lldb_private::DataExtractor& debug_line_data);
+ LineTable::shared_ptr GetLineTable(const dw_offset_t offset) const;
+
+protected:
+ typedef std::map<dw_offset_t, LineTable::shared_ptr> LineTableMap;
+ typedef LineTableMap::iterator LineTableIter;
+ typedef LineTableMap::const_iterator LineTableConstIter;
+
+ LineTableMap m_lineTableMap;
+};
+
+#endif // liblldb_DWARFDebugLine_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
new file mode 100644
index 0000000..0501da8
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
@@ -0,0 +1,48 @@
+//===-- DWARFDebugMacinfo.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugMacinfo.h"
+
+#include "DWARFDebugMacinfoEntry.h"
+#include "SymbolFileDWARF.h"
+
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugMacinfo::DWARFDebugMacinfo()
+{
+}
+
+DWARFDebugMacinfo::~DWARFDebugMacinfo()
+{
+}
+
+void
+DWARFDebugMacinfo::Dump(Stream *s, const DataExtractor& macinfo_data, dw_offset_t offset)
+{
+ DWARFDebugMacinfoEntry maninfo_entry;
+ if (macinfo_data.GetByteSize() == 0)
+ {
+ s->PutCString("< EMPTY >\n");
+ return;
+ }
+ if (offset == DW_INVALID_OFFSET)
+ {
+ offset = 0;
+ while (maninfo_entry.Extract(macinfo_data, &offset))
+ maninfo_entry.Dump(s);
+ }
+ else
+ {
+ if (maninfo_entry.Extract(macinfo_data, &offset))
+ maninfo_entry.Dump(s);
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h
new file mode 100644
index 0000000..e420a5b
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h
@@ -0,0 +1,29 @@
+//===-- DWARFDebugMacinfo.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_DWARFDebugLine_h_
+#define SymbolFileDWARF_DWARFDebugLine_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFDebugMacinfo
+{
+public:
+ DWARFDebugMacinfo();
+
+ ~DWARFDebugMacinfo();
+
+ static void
+ Dump (lldb_private::Stream *s,
+ const lldb_private::DataExtractor& macinfo_data,
+ dw_offset_t offset = DW_INVALID_OFFSET);
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugLine_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
new file mode 100644
index 0000000..c07cec4
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
@@ -0,0 +1,132 @@
+//===-- DWARFDebugMacinfoEntry.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugMacinfoEntry.h"
+
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugMacinfoEntry::DWARFDebugMacinfoEntry() :
+ m_type_code(0),
+ m_line(0),
+ m_op2()
+{
+ m_op2.cstr = NULL;
+}
+
+DWARFDebugMacinfoEntry::~DWARFDebugMacinfoEntry()
+{
+}
+
+const char*
+DWARFDebugMacinfoEntry::GetCString() const
+{
+ switch (m_type_code)
+ {
+ case 0:
+ case DW_MACINFO_start_file:
+ case DW_MACINFO_end_file:
+ return NULL;
+ default:
+ break;
+ }
+ return m_op2.cstr;
+}
+
+
+
+void
+DWARFDebugMacinfoEntry::Dump(Stream *s) const
+{
+ if (m_type_code)
+ {
+ s->PutCString(DW_MACINFO_value_to_name(m_type_code));
+
+ switch (m_type_code)
+ {
+ case DW_MACINFO_define:
+ s->Printf(" line:%u #define %s\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ case DW_MACINFO_undef:
+ s->Printf(" line:%u #undef %s\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ default:
+ s->Printf(" line:%u str: '%s'\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ case DW_MACINFO_start_file:
+ s->Printf(" line:%u file index: '%s'\n", (uint32_t)m_line, (uint32_t)m_op2.file_idx);
+ break;
+
+ case DW_MACINFO_end_file:
+ break;
+ }
+ }
+ else
+ {
+ s->PutCString(" END\n");
+ }
+}
+
+
+bool
+DWARFDebugMacinfoEntry::Extract(const DataExtractor& mac_info_data, dw_offset_t* offset_ptr)
+{
+ if (mac_info_data.ValidOffset(*offset_ptr))
+ {
+ m_type_code = mac_info_data.GetU8(offset_ptr);
+
+ switch (m_type_code)
+ {
+
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ // 2 operands:
+ // Arg 1: operand encodes the line number of the source line on which
+ // the relevant defining or undefining pre-processor directives
+ // appeared.
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ // Arg 2: define string
+ m_op2.cstr = mac_info_data.GetCStr(offset_ptr);
+ break;
+
+ case DW_MACINFO_start_file:
+ // 2 operands:
+ // Op 1: line number of the source line on which the inclusion
+ // pre-processor directive occurred.
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ // Op 2: a source file name index to a file number in the statement
+ // information table for the relevant compilation unit.
+ m_op2.file_idx = mac_info_data.GetULEB128(offset_ptr);
+ break;
+
+ case 0: // End of list
+ case DW_MACINFO_end_file:
+ // No operands
+ m_line = DW_INVALID_OFFSET;
+ m_op2.cstr = NULL;
+ break;
+ default:
+ // Vendor specific entries always have a ULEB128 and a string
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ m_op2.cstr = mac_info_data.GetCStr(offset_ptr);
+ break;
+ }
+ return true;
+ }
+ else
+ m_type_code = 0;
+
+ return false;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h
new file mode 100644
index 0000000..85dd625
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h
@@ -0,0 +1,57 @@
+//===-- DWARFDebugMacinfoEntry.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_DWARFDebugMacinfoEntry_h_
+#define SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFDebugMacinfoEntry
+{
+public:
+ DWARFDebugMacinfoEntry();
+
+ ~DWARFDebugMacinfoEntry();
+
+ uint8_t
+ TypeCode() const
+ {
+ return m_type_code;
+ }
+
+ uint8_t
+ GetLineNumber() const
+ {
+ return m_line;
+ }
+
+ void
+ Dump(lldb_private::Stream *s) const;
+
+ const char*
+ GetCString() const;
+
+ bool
+ Extract(const lldb_private::DataExtractor& mac_info_data,
+ dw_offset_t* offset_ptr);
+
+protected:
+
+private:
+ uint8_t m_type_code;
+ dw_uleb128_t m_line;
+ union
+ {
+ dw_uleb128_t file_idx;
+ const char* cstr;
+ } m_op2;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
new file mode 100644
index 0000000..93ecaed
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
@@ -0,0 +1,297 @@
+//===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugPubnames.h"
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "DWARFDebugInfo.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFCompileUnit.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+
+
+using namespace lldb_private;
+
+DWARFDebugPubnames::DWARFDebugPubnames() :
+ m_sets()
+{
+}
+
+bool
+DWARFDebugPubnames::Extract(const DataExtractor& data)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugPubnames::Extract (byte_size = %zu)",
+ data.GetByteSize());
+ Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES);
+ if (log)
+ log->Printf("DWARFDebugPubnames::Extract (byte_size = %zu)", data.GetByteSize());
+
+ if (data.ValidOffset(0))
+ {
+ uint32_t offset = 0;
+
+ DWARFDebugPubnamesSet set;
+ while (data.ValidOffset(offset))
+ {
+ if (set.Extract(data, &offset))
+ {
+ m_sets.push_back(set);
+ offset = set.GetOffsetOfNextEntry();
+ }
+ else
+ break;
+ }
+ if (log)
+ Dump (log);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugPubnames::GeneratePubnames (data = %p)",
+ dwarf2Data);
+
+ Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES);
+ if (log)
+ log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data);
+
+ m_sets.clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+
+ const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data();
+
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
+
+ DWARFDIECollection dies;
+ const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) +
+ cu->AppendDIEsWithTag (DW_TAG_variable, dies);
+
+ dw_offset_t cu_offset = cu->GetOffset();
+ DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
+
+ size_t die_idx;
+ for (die_idx = 0; die_idx < die_count; ++die_idx)
+ {
+ const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ bool add_die = false;
+ bool is_variable = false;
+ const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ dw_tag_t tag = die->Tag();
+
+ is_variable = tag == DW_TAG_variable;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ name = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ mangled = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_ranges:
+ case DW_AT_entry_pc:
+ if (tag == DW_TAG_subprogram)
+ add_die = true;
+ break;
+
+ case DW_AT_location:
+ if (tag == DW_TAG_variable)
+ {
+ const DWARFDebugInfoEntry* parent_die = die->GetParent();
+ while ( parent_die != NULL )
+ {
+ switch (parent_die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ // Even if this is a function level static, we don't add it. We could theoretically
+ // add these if we wanted to by introspecting into the DW_AT_location and seeing
+ // if the location describes a hard coded address, but we dont want the performance
+ // penalty of that right now.
+ add_die = false;
+// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+// {
+// // If we have valid block data, then we have location expression bytes
+// // that are fixed (not a location list).
+// const uint8_t *block_data = form_value.BlockData();
+// if (block_data)
+// {
+// uint32_t block_length = form_value.Unsigned();
+// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
+// {
+// if (block_data[0] == DW_OP_addr)
+// add_die = true;
+// }
+// }
+// }
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ case DW_TAG_compile_unit:
+ add_die = true;
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ default:
+ parent_die = parent_die->GetParent(); // Keep going in the while loop.
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (add_die && (name || mangled))
+ {
+ if (is_variable)
+ cu->AddGlobal(die);
+ pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name);
+ }
+ }
+
+ if (pubnames_set.NumDescriptors() > 0)
+ {
+ m_sets.push_back(pubnames_set);
+ }
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ cu->ClearDIEs (true);
+ }
+ }
+ if (m_sets.empty())
+ return false;
+ if (log)
+ Dump (log);
+ return true;
+}
+
+bool
+DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data)
+{
+ m_sets.clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ DWARFDIECollection dies;
+ const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies);
+ dw_offset_t cu_offset = cu->GetOffset();
+ DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
+
+ size_t die_idx;
+ for (die_idx = 0; die_idx < die_count; ++die_idx)
+ {
+ const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
+ const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL);
+
+ if (name)
+ {
+ pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name);
+ }
+ }
+
+ if (pubnames_set.NumDescriptors() > 0)
+ {
+ m_sets.push_back(pubnames_set);
+ }
+ }
+ }
+ return !m_sets.empty();
+}
+
+void
+DWARFDebugPubnames::Dump(Log *s) const
+{
+ if (m_sets.empty())
+ s->PutCString("< EMPTY >\n");
+ else
+ {
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ (*pos).Dump(s);
+ }
+}
+
+bool
+DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const
+{
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ die_offsets.clear();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ {
+ (*pos).Find(name, ignore_case, die_offsets);
+ }
+
+ return !die_offsets.empty();
+}
+
+bool
+DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const
+{
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ die_offsets.clear();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ {
+ (*pos).Find(regex, die_offsets);
+ }
+
+ return !die_offsets.empty();
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h
new file mode 100644
index 0000000..7d09bf3
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h
@@ -0,0 +1,38 @@
+//===-- DWARFDebugPubnames.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_DWARFDebugPubnames_h_
+#define SymbolFileDWARF_DWARFDebugPubnames_h_
+
+#include "SymbolFileDWARF.h"
+
+#include <list>
+
+#include "DWARFDebugPubnamesSet.h"
+
+class DWARFDebugPubnames
+{
+public:
+ DWARFDebugPubnames();
+ bool Extract(const lldb_private::DataExtractor& data);
+ bool GeneratePubnames(SymbolFileDWARF* dwarf2Data);
+ bool GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data);
+
+ void Dump(lldb_private::Log *s) const;
+ bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const;
+ bool Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const;
+protected:
+ typedef std::list<DWARFDebugPubnamesSet> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_sets;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugPubnames_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
new file mode 100644
index 0000000..0421ced
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
@@ -0,0 +1,166 @@
+//===-- DWARFDebugPubnamesSet.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugPubnamesSet.h"
+
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Log.h"
+
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+
+DWARFDebugPubnamesSet::DWARFDebugPubnamesSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_header(),
+ m_descriptors(),
+ m_name_to_descriptor_index()
+{
+}
+
+DWARFDebugPubnamesSet::DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t cu_die_length) :
+ m_offset(debug_aranges_offset),
+ m_header(),
+ m_descriptors(),
+ m_name_to_descriptor_index()
+{
+ m_header.length = 10; // set the length to only include the header right for now
+ m_header.version = 2; // The DWARF version number
+ m_header.die_offset = cu_die_offset;// compile unit .debug_info offset
+ m_header.die_length = cu_die_length;// compile unit .debug_info length
+}
+
+void
+DWARFDebugPubnamesSet::AddDescriptor(dw_offset_t cu_rel_offset, const char* name)
+{
+ if (name && name[0])
+ {
+ // Adjust our header length
+ m_header.length += strlen(name) + 1 + sizeof(dw_offset_t);
+ Descriptor pubnameDesc(cu_rel_offset, name);
+ m_descriptors.push_back(pubnameDesc);
+ }
+}
+
+void
+DWARFDebugPubnamesSet::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_header.length = 10;
+ m_header.version = 2;
+ m_header.die_offset = DW_INVALID_OFFSET;
+ m_header.die_length = 0;
+ m_descriptors.clear();
+}
+
+
+//----------------------------------------------------------------------
+// InitNameIndexes
+//----------------------------------------------------------------------
+void
+DWARFDebugPubnamesSet::InitNameIndexes() const
+{
+ // Create the name index vector to be able to quickly search by name
+ const size_t count = m_descriptors.size();
+ for (uint32_t idx = 0; idx < count; ++idx)
+ {
+ const char* name = m_descriptors[idx].name.c_str();
+ if (name && name[0])
+ m_name_to_descriptor_index.insert(cstr_to_index_mmap::value_type(name, idx));
+ }
+}
+
+
+bool
+DWARFDebugPubnamesSet::Extract(const DataExtractor& data, uint32_t* offset_ptr)
+{
+ if (data.ValidOffset(*offset_ptr))
+ {
+ m_descriptors.clear();
+ m_offset = *offset_ptr;
+ m_header.length = data.GetU32(offset_ptr);
+ m_header.version = data.GetU16(offset_ptr);
+ m_header.die_offset = data.GetU32(offset_ptr);
+ m_header.die_length = data.GetU32(offset_ptr);
+
+ Descriptor pubnameDesc;
+ while (data.ValidOffset(*offset_ptr))
+ {
+ pubnameDesc.offset = data.GetU32(offset_ptr);
+
+ if (pubnameDesc.offset)
+ {
+ const char* name = data.GetCStr(offset_ptr);
+ if (name && name[0])
+ {
+ pubnameDesc.name = name;
+ m_descriptors.push_back(pubnameDesc);
+ }
+ }
+ else
+ break; // We are done if we get a zero 4 byte offset
+ }
+
+ return !m_descriptors.empty();
+ }
+ return false;
+}
+
+dw_offset_t
+DWARFDebugPubnamesSet::GetOffsetOfNextEntry() const
+{
+ return m_offset + m_header.length + 4;
+}
+
+void
+DWARFDebugPubnamesSet::Dump(Log *log) const
+{
+ log->Printf("Pubnames Header: length = 0x%8.8x, version = 0x%4.4x, die_offset = 0x%8.8x, die_length = 0x%8.8x",
+ m_header.length,
+ m_header.version,
+ m_header.die_offset,
+ m_header.die_length);
+
+ bool verbose = log->GetVerbose();
+
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_descriptors.end();
+ for (pos = m_descriptors.begin(); pos != end; ++pos)
+ {
+ if (verbose)
+ log->Printf("0x%8.8x + 0x%8.8x = 0x%8.8x: %s", pos->offset, m_header.die_offset, pos->offset + m_header.die_offset, pos->name.c_str());
+ else
+ log->Printf("0x%8.8x: %s", pos->offset + m_header.die_offset, pos->name.c_str());
+ }
+}
+
+
+void
+DWARFDebugPubnamesSet::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const
+{
+ if (!m_descriptors.empty() && m_name_to_descriptor_index.empty())
+ InitNameIndexes();
+
+ std::pair<cstr_to_index_mmap::const_iterator, cstr_to_index_mmap::const_iterator> range(m_name_to_descriptor_index.equal_range(name));
+ for (cstr_to_index_mmap::const_iterator pos = range.first; pos != range.second; ++pos)
+ die_offset_coll.push_back(m_header.die_offset + m_descriptors[(*pos).second].offset);
+}
+
+void
+DWARFDebugPubnamesSet::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offset_coll) const
+{
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_descriptors.end();
+ for (pos = m_descriptors.begin(); pos != end; ++pos)
+ {
+ if ( regex.Execute(pos->name.c_str()) )
+ die_offset_coll.push_back(m_header.die_offset + pos->offset);
+ }
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
new file mode 100644
index 0000000..0597e36
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
@@ -0,0 +1,91 @@
+//===-- DWARFDebugPubnamesSet.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_DWARFDebugPubnamesSet_h_
+#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <string>
+#include <vector>
+#include <ext/hash_map>
+
+class DWARFDebugPubnamesSet
+{
+public:
+ struct Header
+ {
+ uint32_t length; // length of the set of entries for this compilation unit, not including the length field itself
+ uint16_t version; // The DWARF version number
+ uint32_t die_offset; // compile unit .debug_info offset
+ uint32_t die_length; // compile unit .debug_info length
+ Header() :
+ length(10),
+ version(2),
+ die_offset(DW_INVALID_OFFSET),
+ die_length(0)
+ {
+ }
+ };
+
+ struct Descriptor
+ {
+ Descriptor() :
+ offset(),
+ name()
+ {
+ }
+
+ Descriptor(dw_offset_t the_offset, const char *the_name) :
+ offset(the_offset),
+ name(the_name ? the_name : "")
+ {
+ }
+
+ dw_offset_t offset;
+ std::string name;
+ };
+
+ DWARFDebugPubnamesSet();
+ DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t die_length);
+ dw_offset_t GetOffset() const { return m_offset; }
+ void SetOffset(dw_offset_t offset) { m_offset = offset; }
+ DWARFDebugPubnamesSet::Header& GetHeader() { return m_header; }
+ const DWARFDebugPubnamesSet::Header& GetHeader() const { return m_header; }
+ const DWARFDebugPubnamesSet::Descriptor* GetDescriptor(uint32_t i) const
+ {
+ if (i < m_descriptors.size())
+ return &m_descriptors[i];
+ return NULL;
+ }
+ uint32_t NumDescriptors() const { return m_descriptors.size(); }
+ void AddDescriptor(dw_offset_t cu_rel_offset, const char* name);
+ void Clear();
+ bool Extract(const lldb_private::DataExtractor& debug_pubnames_data, uint32_t* offset_ptr);
+ void Dump(lldb_private::Log *s) const;
+ void InitNameIndexes() const;
+ void Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const;
+ void Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const;
+ dw_offset_t GetOffsetOfNextEntry() const;
+
+
+
+protected:
+ typedef std::vector<Descriptor> DescriptorColl;
+ typedef DescriptorColl::iterator DescriptorIter;
+ typedef DescriptorColl::const_iterator DescriptorConstIter;
+
+
+ dw_offset_t m_offset;
+ Header m_header;
+ typedef __gnu_cxx::hash_multimap<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap;
+ DescriptorColl m_descriptors;
+ mutable cstr_to_index_mmap m_name_to_descriptor_index;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
new file mode 100644
index 0000000..62da228
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
@@ -0,0 +1,275 @@
+//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugRanges.h"
+#include "SymbolFileDWARF.h"
+#include "lldb/Core/Stream.h"
+#include <assert.h>
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugRanges::DWARFDebugRanges() :
+ m_range_map()
+{
+}
+
+DWARFDebugRanges::~DWARFDebugRanges()
+{
+}
+
+void
+DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data)
+{
+ RangeList range_list;
+ dw_offset_t offset = 0;
+ dw_offset_t debug_ranges_offset = offset;
+ while (range_list.Extract(dwarf2Data, &offset))
+ {
+ m_range_map[debug_ranges_offset] = range_list;
+ debug_ranges_offset = offset;
+ }
+}
+
+bool
+DWARFDebugRanges::RangeList::AddRange(dw_addr_t lo_addr, dw_addr_t hi_addr)
+{
+ if (lo_addr <= hi_addr)
+ {
+ Range range(lo_addr, hi_addr);
+ ranges.push_back(range);
+ return true;
+ }
+ return false;
+}
+
+const DWARFDebugRanges::Range*
+DWARFDebugRanges::RangeList::Lookup(dw_addr_t offset) const
+{
+ Range::const_iterator pos = ranges.begin();
+ Range::const_iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->begin_offset <= offset && offset < pos->end_offset)
+ {
+ return &(*pos);
+ }
+ }
+ return NULL;
+}
+
+size_t
+DWARFDebugRanges::RangeList::Size() const
+{
+ return ranges.size();
+}
+
+void
+DWARFDebugRanges::RangeList::AddOffset(dw_addr_t offset)
+{
+ if (!ranges.empty())
+ {
+ Range::iterator pos = ranges.begin();
+ Range::iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ // assert for unsigned overflows
+ assert (~pos->begin_offset >= offset);
+ assert (~pos->end_offset >= offset);
+ pos->begin_offset += offset;
+ pos->end_offset += offset;
+ }
+ }
+}
+
+void
+DWARFDebugRanges::RangeList::SubtractOffset(dw_addr_t offset)
+{
+ if (!ranges.empty())
+ {
+ Range::iterator pos = ranges.begin();
+ Range::iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ assert (pos->begin_offset >= offset);
+ assert (pos->end_offset >= offset);
+ pos->begin_offset -= offset;
+ pos->end_offset -= offset;
+ }
+ }
+}
+
+
+const DWARFDebugRanges::Range*
+DWARFDebugRanges::RangeList::RangeAtIndex(size_t i) const
+{
+ if (i < ranges.size())
+ return &ranges[i];
+ return NULL;
+}
+
+bool
+DWARFDebugRanges::RangeList::Extract(SymbolFileDWARF* dwarf2Data, uint32_t* offset_ptr)
+{
+ Clear();
+ uint32_t range_offset = *offset_ptr;
+ const DataExtractor& debug_ranges_data = dwarf2Data->get_debug_ranges_data();
+ uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
+
+ while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size))
+ {
+ dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ if (!begin && !end)
+ {
+ // End of range list
+ break;
+ }
+ // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits
+ // of ones
+ switch (addr_size)
+ {
+ case 2:
+ if (begin == 0xFFFFull)
+ begin = DW_INVALID_ADDRESS;
+ break;
+
+ case 4:
+ if (begin == 0xFFFFFFFFull)
+ begin = DW_INVALID_ADDRESS;
+ break;
+
+ case 8:
+ break;
+
+ default:
+ assert(!"DWARFDebugRanges::RangeList::Extract() unsupported address size.");
+ break;
+ }
+
+ // Filter out empty ranges
+ if (begin != end)
+ ranges.push_back(Range(begin, end));
+ }
+
+ // Make sure we consumed at least something
+ return range_offset != *offset_ptr;
+}
+
+
+dw_addr_t
+DWARFDebugRanges::RangeList::LowestAddress(const dw_addr_t cu_base_addr) const
+{
+ dw_addr_t addr = DW_INVALID_ADDRESS;
+ dw_addr_t curr_base_addr = cu_base_addr;
+ if (!ranges.empty())
+ {
+ Range::const_iterator pos = ranges.begin();
+ Range::const_iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->begin_offset == DW_INVALID_ADDRESS)
+ curr_base_addr = pos->end_offset;
+ else if (curr_base_addr != DW_INVALID_ADDRESS)
+ {
+ dw_addr_t curr_addr = curr_base_addr + pos->begin_offset;
+ if (addr > curr_addr)
+ addr = curr_addr;
+ }
+ }
+ }
+ return addr;
+}
+
+dw_addr_t
+DWARFDebugRanges::RangeList::HighestAddress(const dw_addr_t cu_base_addr) const
+{
+ dw_addr_t addr = 0;
+ dw_addr_t curr_base_addr = cu_base_addr;
+ if (!ranges.empty())
+ {
+ Range::const_iterator pos = ranges.begin();
+ Range::const_iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->begin_offset == DW_INVALID_ADDRESS)
+ curr_base_addr = pos->end_offset;
+ else if (curr_base_addr != DW_INVALID_ADDRESS)
+ {
+ dw_addr_t curr_addr = curr_base_addr + pos->end_offset;
+ if (addr < curr_addr)
+ addr = curr_addr;
+ }
+ }
+ }
+ if (addr != 0)
+ return addr;
+ return DW_INVALID_ADDRESS;
+}
+
+
+void
+DWARFDebugRanges::Dump(Stream *s, const DataExtractor& debug_ranges_data, uint32_t* offset_ptr, dw_addr_t cu_base_addr)
+{
+ uint32_t addr_size = s->GetAddressByteSize();
+ bool verbose = s->GetVerbose();
+
+ dw_addr_t base_addr = cu_base_addr;
+ while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size))
+ {
+ dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits
+ // of ones
+ if (begin == 0xFFFFFFFFull && addr_size == 4)
+ begin = DW_INVALID_ADDRESS;
+
+ s->Indent();
+ if (verbose)
+ {
+ s->AddressRange(begin, end, sizeof (dw_addr_t), " offsets = ");
+ }
+
+
+ if (begin == 0 && end == 0)
+ {
+ s->PutCString(" End");
+ break;
+ }
+ else if (begin == DW_INVALID_ADDRESS)
+ {
+ // A base address selection entry
+ base_addr = end;
+ s->Address(base_addr, sizeof (dw_addr_t), " Base address = ");
+ }
+ else
+ {
+ // Convert from offset to an address
+ dw_addr_t begin_addr = begin + base_addr;
+ dw_addr_t end_addr = end + base_addr;
+
+ s->AddressRange(begin_addr, end_addr, sizeof (dw_addr_t), verbose ? " ==> addrs = " : NULL);
+ }
+ }
+}
+
+bool
+DWARFDebugRanges::FindRanges(dw_offset_t debug_ranges_offset, RangeList& range_list) const
+{
+ range_map_const_iterator pos = m_range_map.find(debug_ranges_offset);
+ if (pos != m_range_map.end())
+ {
+ range_list = pos->second;
+ return true;
+ }
+ return false;
+}
+
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
new file mode 100644
index 0000000..607c3c2
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
@@ -0,0 +1,89 @@
+//===-- DWARFDebugRanges.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_DWARFDebugRanges_h_
+#define liblldb_DWARFDebugRanges_h_
+
+#include "SymbolFileDWARF.h"
+#include <map>
+#include <vector>
+
+
+class DWARFDebugRanges
+{
+public:
+
+ //------------------------------------------------------------------
+ // Address range
+ //------------------------------------------------------------------
+ struct Range
+ {
+ Range(dw_addr_t begin = DW_INVALID_ADDRESS, dw_addr_t end = DW_INVALID_ADDRESS) :
+ begin_offset(begin),
+ end_offset(end)
+ {
+ }
+
+ void Clear()
+ {
+ begin_offset = DW_INVALID_ADDRESS;
+ end_offset = DW_INVALID_ADDRESS;
+ }
+
+ dw_addr_t begin_offset;
+ dw_addr_t end_offset;
+
+ typedef std::vector<Range> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ };
+
+ //------------------------------------------------------------------
+ // Collection of ranges
+ //------------------------------------------------------------------
+ struct RangeList
+ {
+ RangeList() :
+ ranges()
+ {
+ }
+
+ bool Extract(SymbolFileDWARF* dwarf2Data, uint32_t* offset_ptr);
+ bool AddRange(dw_addr_t lo_addr, dw_addr_t hi_addr);
+ void Clear()
+ {
+ ranges.clear();
+ }
+
+ dw_addr_t LowestAddress(const dw_addr_t base_addr) const;
+ dw_addr_t HighestAddress(const dw_addr_t base_addr) const;
+ void AddOffset(dw_addr_t offset);
+ void SubtractOffset(dw_addr_t offset);
+ size_t Size() const;
+ const Range* RangeAtIndex(size_t i) const;
+ const Range* Lookup(dw_addr_t offset) const;
+ Range::collection ranges;
+ };
+
+ DWARFDebugRanges();
+ ~DWARFDebugRanges();
+ void Extract(SymbolFileDWARF* dwarf2Data);
+ static void Dump(lldb_private::Stream *s, const lldb_private::DataExtractor& debug_ranges_data, uint32_t* offset_ptr, dw_addr_t cu_base_addr);
+ bool FindRanges(dw_offset_t debug_ranges_offset, DWARFDebugRanges::RangeList& range_list) const;
+
+protected:
+ typedef std::map<dw_offset_t, RangeList> range_map;
+ typedef range_map::iterator range_map_iterator;
+ typedef range_map::const_iterator range_map_const_iterator;
+ range_map m_range_map;
+};
+
+
+#endif // liblldb_DWARFDebugRanges_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.c b/source/Plugins/SymbolFile/DWARF/DWARFDefines.c
new file mode 100644
index 0000000..fe487f9
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.c
@@ -0,0 +1,2224 @@
+//===-- DWARFDefines.c ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDefines.h"
+#include <stdio.h>
+
+#define DW_TAG_PREFIX "TAG_"
+#define DW_AT_PREFIX " AT_"
+#define DW_FORM_PREFIX "FORM_"
+
+/* [7.5.4] Figure 16 "Tag Encodings" (pp. 125-127) in DWARFv3 draft 8 */
+
+const char *
+DW_TAG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0000: return DW_TAG_PREFIX "NULL";
+ case 0x0001: return DW_TAG_PREFIX "array_type";
+ case 0x0002: return DW_TAG_PREFIX "class_type";
+ case 0x0003: return DW_TAG_PREFIX "entry_point";
+ case 0x0004: return DW_TAG_PREFIX "enumeration_type";
+ case 0x0005: return DW_TAG_PREFIX "formal_parameter";
+ case 0x0008: return DW_TAG_PREFIX "imported_declaration";
+ case 0x000a: return DW_TAG_PREFIX "label";
+ case 0x000b: return DW_TAG_PREFIX "lexical_block";
+ case 0x000d: return DW_TAG_PREFIX "member";
+ case 0x000f: return DW_TAG_PREFIX "pointer_type";
+ case 0x0010: return DW_TAG_PREFIX "reference_type";
+ case 0x0011: return DW_TAG_PREFIX "compile_unit";
+ case 0x0012: return DW_TAG_PREFIX "string_type";
+ case 0x0013: return DW_TAG_PREFIX "structure_type";
+ case 0x0015: return DW_TAG_PREFIX "subroutine_type";
+ case 0x0016: return DW_TAG_PREFIX "typedef";
+ case 0x0017: return DW_TAG_PREFIX "union_type";
+ case 0x0018: return DW_TAG_PREFIX "unspecified_parameters";
+ case 0x0019: return DW_TAG_PREFIX "variant";
+ case 0x001a: return DW_TAG_PREFIX "common_block";
+ case 0x001b: return DW_TAG_PREFIX "common_inclusion";
+ case 0x001c: return DW_TAG_PREFIX "inheritance";
+ case 0x001d: return DW_TAG_PREFIX "inlined_subroutine";
+ case 0x001e: return DW_TAG_PREFIX "module";
+ case 0x001f: return DW_TAG_PREFIX "ptr_to_member_type";
+ case 0x0020: return DW_TAG_PREFIX "set_type";
+ case 0x0021: return DW_TAG_PREFIX "subrange_type";
+ case 0x0022: return DW_TAG_PREFIX "with_stmt";
+ case 0x0023: return DW_TAG_PREFIX "access_declaration";
+ case 0x0024: return DW_TAG_PREFIX "base_type";
+ case 0x0025: return DW_TAG_PREFIX "catch_block";
+ case 0x0026: return DW_TAG_PREFIX "const_type";
+ case 0x0027: return DW_TAG_PREFIX "constant";
+ case 0x0028: return DW_TAG_PREFIX "enumerator";
+ case 0x0029: return DW_TAG_PREFIX "file_type";
+ case 0x002a: return DW_TAG_PREFIX "friend";
+ case 0x002b: return DW_TAG_PREFIX "namelist";
+ case 0x002c: return DW_TAG_PREFIX "namelist_item";
+ case 0x002d: return DW_TAG_PREFIX "packed_type";
+ case 0x002e: return DW_TAG_PREFIX "subprogram";
+ case 0x002f: return DW_TAG_PREFIX "template_type_parameter";
+ case 0x0030: return DW_TAG_PREFIX "template_value_parameter";
+ case 0x0031: return DW_TAG_PREFIX "thrown_type";
+ case 0x0032: return DW_TAG_PREFIX "try_block";
+ case 0x0033: return DW_TAG_PREFIX "variant_part";
+ case 0x0034: return DW_TAG_PREFIX "variable";
+ case 0x0035: return DW_TAG_PREFIX "volatile_type";
+ case 0x0036: return DW_TAG_PREFIX "dwarf_procedure";
+ case 0x0037: return DW_TAG_PREFIX "restrict_type";
+ case 0x0038: return DW_TAG_PREFIX "interface_type";
+ case 0x0039: return DW_TAG_PREFIX "namespace";
+ case 0x003a: return DW_TAG_PREFIX "imported_module";
+ case 0x003b: return DW_TAG_PREFIX "unspecified_type";
+ case 0x003c: return DW_TAG_PREFIX "partial_unit";
+ case 0x003d: return DW_TAG_PREFIX "imported_unit";
+// case 0x003d: return DW_TAG_PREFIX "condition";
+ case 0x0040: return DW_TAG_PREFIX "shared_type";
+ case 0x4080: return DW_TAG_PREFIX "lo_user";
+ case 0xffff: return DW_TAG_PREFIX "hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_TAG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_TAG_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "array type";
+ case 0x0002: return "class type";
+ case 0x0003: return "entry point";
+ case 0x0004: return "enumeration type";
+ case 0x0005: return "formal parameter";
+ case 0x0008: return "imported declaration";
+ case 0x000a: return "label";
+ case 0x000b: return "lexical block";
+ case 0x000d: return "member";
+ case 0x000f: return "pointer type";
+ case 0x0010: return "reference type";
+ case 0x0011: return "file";
+ case 0x0012: return "string type";
+ case 0x0013: return "structure type";
+ case 0x0015: return "subroutine type";
+ case 0x0016: return "typedef";
+ case 0x0017: return "union type";
+ case 0x0018: return "unspecified parameters";
+ case 0x0019: return "variant";
+ case 0x001a: return "common block";
+ case 0x001b: return "common inclusion";
+ case 0x001c: return "inheritance";
+ case 0x001d: return "inlined subroutine";
+ case 0x001e: return "module";
+ case 0x001f: return "ptr to member type";
+ case 0x0020: return "set type";
+ case 0x0021: return "subrange type";
+ case 0x0022: return "with stmt";
+ case 0x0023: return "access declaration";
+ case 0x0024: return "base type";
+ case 0x0025: return "catch block";
+ case 0x0026: return "const type";
+ case 0x0027: return "constant";
+ case 0x0028: return "enumerator";
+ case 0x0029: return "file type";
+ case 0x002a: return "friend";
+ case 0x002b: return "namelist";
+ case 0x002c: return "namelist item";
+ case 0x002d: return "packed type";
+ case 0x002e: return "function";
+ case 0x002f: return "template type parameter";
+ case 0x0030: return "template value parameter";
+ case 0x0031: return "thrown type";
+ case 0x0032: return "try block";
+ case 0x0033: return "variant part";
+ case 0x0034: return "variable";
+ case 0x0035: return "volatile type";
+ case 0x0036: return "dwarf procedure";
+ case 0x0037: return "restrict type";
+ case 0x0038: return "interface type";
+ case 0x0039: return "namespace";
+ case 0x003a: return "imported module";
+ case 0x003b: return "unspecified type";
+ case 0x003c: return "partial unit";
+ case 0x003d: return "imported unit";
+// case 0x003d: return "condition";
+ case 0x0040: return "shared type";
+ case 0x4080: return "lo user";
+ case 0xffff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_TAG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_TAG_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0001: return 0;
+ case 0x0002: return 0;
+ case 0x0003: return 0;
+ case 0x0004: return 0;
+ case 0x0005: return 0;
+ case 0x0008: return 0;
+ case 0x000a: return 0;
+ case 0x000b: return 0;
+ case 0x000d: return 0;
+ case 0x000f: return 0;
+ case 0x0010: return 0;
+ case 0x0011: return 0;
+ case 0x0012: return 0;
+ case 0x0013: return 0;
+ case 0x0015: return 0;
+ case 0x0016: return 0;
+ case 0x0017: return 0;
+ case 0x0018: return 0;
+ case 0x0019: return 0;
+ case 0x001a: return 0;
+ case 0x001b: return 0;
+ case 0x001c: return 0;
+ case 0x001d: return 0;
+ case 0x001e: return 0;
+ case 0x001f: return 0;
+ case 0x0020: return 0;
+ case 0x0021: return 0;
+ case 0x0022: return 0;
+ case 0x0023: return 0;
+ case 0x0024: return 0;
+ case 0x0025: return 0;
+ case 0x0026: return 0;
+ case 0x0027: return 0;
+ case 0x0028: return 0;
+ case 0x0029: return 0;
+ case 0x002a: return 0;
+ case 0x002b: return 0;
+ case 0x002c: return 0;
+ case 0x002d: return 0;
+ case 0x002e: return 0;
+ case 0x002f: return 0;
+ case 0x0030: return 0;
+ case 0x0031: return 0;
+ case 0x0032: return 0;
+ case 0x0033: return 0;
+ case 0x0034: return 0;
+ case 0x0035: return 0;
+ case 0x0036: return DRC_DWARFv3;
+ case 0x0037: return DRC_DWARFv3;
+ case 0x0038: return DRC_DWARFv3;
+ case 0x0039: return DRC_DWARFv3;
+ case 0x003a: return DRC_DWARFv3;
+ case 0x003b: return DRC_DWARFv3;
+ case 0x003c: return DRC_DWARFv3;
+ case 0x003d: return DRC_DWARFv3;
+// case 0x003d: return DRC_DWARFv3;
+ case 0x0040: return DRC_DWARFv3;
+ case 0x4080: return 0;
+ case 0xffff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.5.4] Figure 17 "Child determination encodings" (p. 128) in DWARFv3 draft 8 */
+
+const char *
+DW_CHILDREN_value_to_name (uint8_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_CHILDREN_no";
+ case 0x1: return "DW_CHILDREN_yes";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CHILDREN constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_CHILDREN_value_to_englishy_name (uint8_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "no";
+ case 0x1: return "yes";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CHILDREN constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_CHILDREN_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.5.4] Figure 18 "Attribute encodings" (pp. 129-132) in DWARFv3 draft 8 */
+
+const char *
+DW_AT_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return DW_AT_PREFIX "sibling";
+ case 0x0002: return DW_AT_PREFIX "location";
+ case 0x0003: return DW_AT_PREFIX "name";
+ case 0x0009: return DW_AT_PREFIX "ordering";
+ case 0x000b: return DW_AT_PREFIX "byte_size";
+ case 0x000c: return DW_AT_PREFIX "bit_offset";
+ case 0x000d: return DW_AT_PREFIX "bit_size";
+ case 0x0010: return DW_AT_PREFIX "stmt_list";
+ case 0x0011: return DW_AT_PREFIX "low_pc";
+ case 0x0012: return DW_AT_PREFIX "high_pc";
+ case 0x0013: return DW_AT_PREFIX "language";
+ case 0x0015: return DW_AT_PREFIX "discr";
+ case 0x0016: return DW_AT_PREFIX "discr_value";
+ case 0x0017: return DW_AT_PREFIX "visibility";
+ case 0x0018: return DW_AT_PREFIX "import";
+ case 0x0019: return DW_AT_PREFIX "string_length";
+ case 0x001a: return DW_AT_PREFIX "common_reference";
+ case 0x001b: return DW_AT_PREFIX "comp_dir";
+ case 0x001c: return DW_AT_PREFIX "const_value";
+ case 0x001d: return DW_AT_PREFIX "containing_type";
+ case 0x001e: return DW_AT_PREFIX "default_value";
+ case 0x0020: return DW_AT_PREFIX "inline";
+ case 0x0021: return DW_AT_PREFIX "is_optional";
+ case 0x0022: return DW_AT_PREFIX "lower_bound";
+ case 0x0025: return DW_AT_PREFIX "producer";
+ case 0x0027: return DW_AT_PREFIX "prototyped";
+ case 0x002a: return DW_AT_PREFIX "return_addr";
+ case 0x002c: return DW_AT_PREFIX "start_scope";
+ case 0x002e: return DW_AT_PREFIX "bit_stride";
+ case 0x002f: return DW_AT_PREFIX "upper_bound";
+ case 0x0031: return DW_AT_PREFIX "abstract_origin";
+ case 0x0032: return DW_AT_PREFIX "accessibility";
+ case 0x0033: return DW_AT_PREFIX "address_class";
+ case 0x0034: return DW_AT_PREFIX "artificial";
+ case 0x0035: return DW_AT_PREFIX "base_types";
+ case 0x0036: return DW_AT_PREFIX "calling_convention";
+ case 0x0037: return DW_AT_PREFIX "count";
+ case 0x0038: return DW_AT_PREFIX "data_member_location";
+ case 0x0039: return DW_AT_PREFIX "decl_column";
+ case 0x003a: return DW_AT_PREFIX "decl_file";
+ case 0x003b: return DW_AT_PREFIX "decl_line";
+ case 0x003c: return DW_AT_PREFIX "declaration";
+ case 0x003d: return DW_AT_PREFIX "discr_list";
+ case 0x003e: return DW_AT_PREFIX "encoding";
+ case 0x003f: return DW_AT_PREFIX "external";
+ case 0x0040: return DW_AT_PREFIX "frame_base";
+ case 0x0041: return DW_AT_PREFIX "friend";
+ case 0x0042: return DW_AT_PREFIX "identifier_case";
+ case 0x0043: return DW_AT_PREFIX "macro_info";
+ case 0x0044: return DW_AT_PREFIX "namelist_item";
+ case 0x0045: return DW_AT_PREFIX "priority";
+ case 0x0046: return DW_AT_PREFIX "segment";
+ case 0x0047: return DW_AT_PREFIX "specification";
+ case 0x0048: return DW_AT_PREFIX "static_link";
+ case 0x0049: return DW_AT_PREFIX "type";
+ case 0x004a: return DW_AT_PREFIX "use_location";
+ case 0x004b: return DW_AT_PREFIX "variable_parameter";
+ case 0x004c: return DW_AT_PREFIX "virtuality";
+ case 0x004d: return DW_AT_PREFIX "vtable_elem_location";
+ case 0x004e: return DW_AT_PREFIX "allocated";
+ case 0x004f: return DW_AT_PREFIX "associated";
+ case 0x0050: return DW_AT_PREFIX "data_location";
+ case 0x0051: return DW_AT_PREFIX "byte_stride";
+ case 0x0052: return DW_AT_PREFIX "entry_pc";
+ case 0x0053: return DW_AT_PREFIX "use_UTF8";
+ case 0x0054: return DW_AT_PREFIX "extension";
+ case 0x0055: return DW_AT_PREFIX "ranges";
+ case 0x0056: return DW_AT_PREFIX "trampoline";
+ case 0x0057: return DW_AT_PREFIX "call_column";
+ case 0x0058: return DW_AT_PREFIX "call_file";
+ case 0x0059: return DW_AT_PREFIX "call_line";
+ case 0x005a: return DW_AT_PREFIX "description";
+ case 0x005b: return DW_AT_PREFIX "binary_scale";
+ case 0x005c: return DW_AT_PREFIX "decimal_scale";
+ case 0x005d: return DW_AT_PREFIX "small";
+ case 0x005e: return DW_AT_PREFIX "decimal_sign";
+ case 0x005f: return DW_AT_PREFIX "digit_count";
+ case 0x0060: return DW_AT_PREFIX "picture_string";
+ case 0x0061: return DW_AT_PREFIX "mutable";
+ case 0x0062: return DW_AT_PREFIX "threads_scaled";
+ case 0x0063: return DW_AT_PREFIX "explicit";
+ case 0x0064: return DW_AT_PREFIX "object_pointer";
+ case 0x0065: return DW_AT_PREFIX "endianity";
+ case 0x0066: return DW_AT_PREFIX "elemental";
+ case 0x0067: return DW_AT_PREFIX "pure";
+ case 0x0068: return DW_AT_PREFIX "recursive";
+ case 0x2000: return DW_AT_PREFIX "lo_user";
+ case 0x3fff: return DW_AT_PREFIX "hi_user";
+ case 0x2001: return DW_AT_PREFIX "MIPS_fde";
+ case 0x2002: return DW_AT_PREFIX "MIPS_loop_begin";
+ case 0x2003: return DW_AT_PREFIX "MIPS_tail_loop_begin";
+ case 0x2004: return DW_AT_PREFIX "MIPS_epilog_begin";
+ case 0x2005: return DW_AT_PREFIX "MIPS_loop_unroll_factor";
+ case 0x2006: return DW_AT_PREFIX "MIPS_software_pipeline_depth";
+ case 0x2007: return DW_AT_PREFIX "MIPS_linkage_name";
+ case 0x2008: return DW_AT_PREFIX "MIPS_stride";
+ case 0x2009: return DW_AT_PREFIX "MIPS_abstract_name";
+ case 0x200a: return DW_AT_PREFIX "MIPS_clone_origin";
+ case 0x200b: return DW_AT_PREFIX "MIPS_has_inlines";
+ case 0x2101: return DW_AT_PREFIX "sf_names";
+ case 0x2102: return DW_AT_PREFIX "src_info";
+ case 0x2103: return DW_AT_PREFIX "mac_info";
+ case 0x2104: return DW_AT_PREFIX "src_coords";
+ case 0x2105: return DW_AT_PREFIX "body_begin";
+ case 0x2106: return DW_AT_PREFIX "body_end";
+ case 0x2107: return DW_AT_PREFIX "GNU_vector";
+ case 0x2501: return DW_AT_PREFIX "APPLE_repository_file";
+ case 0x2502: return DW_AT_PREFIX "APPLE_repository_type";
+ case 0x2503: return DW_AT_PREFIX "APPLE_repository_name";
+ case 0x2504: return DW_AT_PREFIX "APPLE_repository_specification";
+ case 0x2505: return DW_AT_PREFIX "APPLE_repository_import";
+ case 0x2506: return DW_AT_PREFIX "APPLE_repository_abstract_origin";
+ case DW_AT_APPLE_flags: return DW_AT_PREFIX "APPLE_flags";
+ case DW_AT_APPLE_optimized: return DW_AT_PREFIX "APPLE_optimized";
+ case DW_AT_APPLE_isa: return DW_AT_PREFIX "APPLE_isa";
+ case DW_AT_APPLE_block: return DW_AT_PREFIX "APPLE_block";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_AT constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_AT_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "sibling";
+ case 0x0002: return "location";
+ case 0x0003: return "name";
+ case 0x0009: return "ordering";
+ case 0x000b: return "byte size";
+ case 0x000c: return "bit offset";
+ case 0x000d: return "bit size";
+ case 0x0010: return "stmt list";
+ case 0x0011: return "low pc";
+ case 0x0012: return "high pc";
+ case 0x0013: return "language";
+ case 0x0015: return "discr";
+ case 0x0016: return "discr value";
+ case 0x0017: return "visibility";
+ case 0x0018: return "import";
+ case 0x0019: return "string length";
+ case 0x001a: return "common reference";
+ case 0x001b: return "comp dir";
+ case 0x001c: return "const value";
+ case 0x001d: return "containing type";
+ case 0x001e: return "default value";
+ case 0x0020: return "inline";
+ case 0x0021: return "is optional";
+ case 0x0022: return "lower bound";
+ case 0x0025: return "producer";
+ case 0x0027: return "prototyped";
+ case 0x002a: return "return addr";
+ case 0x002c: return "start scope";
+ case 0x002e: return "bit stride";
+ case 0x002f: return "upper bound";
+ case 0x0031: return "abstract origin";
+ case 0x0032: return "accessibility";
+ case 0x0033: return "address class";
+ case 0x0034: return "artificial";
+ case 0x0035: return "base types";
+ case 0x0036: return "calling convention";
+ case 0x0037: return "count";
+ case 0x0038: return "data member location";
+ case 0x0039: return "decl column";
+ case 0x003a: return "decl file";
+ case 0x003b: return "decl line";
+ case 0x003c: return "declaration";
+ case 0x003d: return "discr list";
+ case 0x003e: return "encoding";
+ case 0x003f: return "external";
+ case 0x0040: return "frame base";
+ case 0x0041: return "friend";
+ case 0x0042: return "identifier case";
+ case 0x0043: return "macro info";
+ case 0x0044: return "namelist item";
+ case 0x0045: return "priority";
+ case 0x0046: return "segment";
+ case 0x0047: return "specification";
+ case 0x0048: return "static link";
+ case 0x0049: return "type";
+ case 0x004a: return "use location";
+ case 0x004b: return "variable parameter";
+ case 0x004c: return "virtuality";
+ case 0x004d: return "vtable elem location";
+ case 0x004e: return "allocated";
+ case 0x004f: return "associated";
+ case 0x0050: return "data location";
+ case 0x0051: return "byte stride";
+ case 0x0052: return "entry pc";
+ case 0x0053: return "use UTF8";
+ case 0x0054: return "extension";
+ case 0x0055: return "ranges";
+ case 0x0056: return "trampoline";
+ case 0x0057: return "call column";
+ case 0x0058: return "call file";
+ case 0x0059: return "call line";
+ case 0x005a: return "description";
+ case 0x005b: return "binary scale";
+ case 0x005c: return "decimal scale";
+ case 0x005d: return "small";
+ case 0x005e: return "decimal sign";
+ case 0x005f: return "digit count";
+ case 0x0060: return "picture string";
+ case 0x0061: return "mutable";
+ case 0x0062: return "threads scaled";
+ case 0x0063: return "explicit";
+ case 0x0064: return "object pointer";
+ case 0x0065: return "endianity";
+ case 0x0066: return "elemental";
+ case 0x0067: return "pure";
+ case 0x0068: return "recursive";
+ case 0x2000: return "lo user";
+ case 0x3fff: return "hi user";
+ case 0x2001: return "MIPS fde";
+ case 0x2002: return "MIPS loop begin";
+ case 0x2003: return "MIPS tail loop begin";
+ case 0x2004: return "MIPS epilog begin";
+ case 0x2005: return "MIPS loop unroll factor";
+ case 0x2006: return "MIPS software pipeline depth";
+ case 0x2007: return "MIPS linkage name";
+ case 0x2008: return "MIPS stride";
+ case 0x2009: return "MIPS abstract name";
+ case 0x200a: return "MIPS clone origin";
+ case 0x200b: return "MIPS has inlines";
+ case 0x2101: return "source file names";
+ case 0x2102: return "source info";
+ case 0x2103: return "macro info";
+ case 0x2104: return "source coordinates";
+ case 0x2105: return "body begin";
+ case 0x2106: return "body end";
+ case 0x2107: return "GNU vector";
+ case 0x2501: return "repository file";
+ case 0x2502: return "repository type";
+ case 0x2503: return "repository name";
+ case 0x2504: return "repository specification";
+ case 0x2505: return "repository import";
+ case 0x2506: return "repository abstract origin";
+ case DW_AT_APPLE_flags: return "Apple gcc compiler flags";
+ case DW_AT_APPLE_optimized: return "APPLE optimized";
+ case DW_AT_APPLE_isa: return "APPLE instruction set architecture";
+ case DW_AT_APPLE_block: return "APPLE block";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_AT constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_AT_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0001: return DRC_REFERENCE;
+ case 0x0002: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0003: return DRC_STRING;
+ case 0x0009: return DRC_CONSTANT;
+ case 0x000b: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x000c: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x000d: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0010: return DRC_LINEPTR;
+ case 0x0011: return DRC_ADDRESS;
+ case 0x0012: return DRC_ADDRESS;
+ case 0x0013: return DRC_CONSTANT;
+ case 0x0015: return DRC_REFERENCE;
+ case 0x0016: return DRC_CONSTANT;
+ case 0x0017: return DRC_CONSTANT;
+ case 0x0018: return DRC_REFERENCE;
+ case 0x0019: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x001a: return DRC_REFERENCE;
+ case 0x001b: return DRC_STRING;
+ case 0x001c: return DRC_BLOCK | DRC_CONSTANT | DRC_STRING;
+ case 0x001d: return DRC_REFERENCE;
+ case 0x001e: return DRC_REFERENCE;
+ case 0x0020: return DRC_CONSTANT;
+ case 0x0021: return DRC_FLAG;
+ case 0x0022: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0025: return DRC_STRING;
+ case 0x0027: return DRC_FLAG;
+ case 0x002a: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x002c: return DRC_CONSTANT;
+ case 0x002e: return DRC_CONSTANT;
+ case 0x002f: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0031: return DRC_REFERENCE;
+ case 0x0032: return DRC_CONSTANT;
+ case 0x0033: return DRC_CONSTANT;
+ case 0x0034: return DRC_FLAG;
+ case 0x0035: return DRC_REFERENCE;
+ case 0x0036: return DRC_CONSTANT;
+ case 0x0037: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0038: return DRC_BLOCK | DRC_CONSTANT | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0039: return DRC_CONSTANT;
+ case 0x003a: return DRC_CONSTANT;
+ case 0x003b: return DRC_CONSTANT;
+ case 0x003c: return DRC_FLAG;
+ case 0x003d: return DRC_BLOCK;
+ case 0x003e: return DRC_CONSTANT;
+ case 0x003f: return DRC_FLAG;
+ case 0x0040: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0041: return DRC_REFERENCE;
+ case 0x0042: return DRC_CONSTANT;
+ case 0x0043: return DRC_MACPTR;
+ case 0x0044: return DRC_BLOCK;
+ case 0x0045: return DRC_REFERENCE;
+ case 0x0046: return DRC_BLOCK | DRC_CONSTANT;
+ case 0x0047: return DRC_REFERENCE;
+ case 0x0048: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0049: return DRC_REFERENCE;
+ case 0x004a: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x004b: return DRC_FLAG;
+ case 0x004c: return DRC_CONSTANT;
+ case 0x004d: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x004e: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x004f: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0050: return DRC_BLOCK | DRC_DWARFv3;
+ case 0x0051: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0052: return DRC_ADDRESS | DRC_DWARFv3;
+ case 0x0053: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0054: return DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0055: return DRC_DWARFv3 | DRC_RANGELISTPTR;
+ case 0x0056: return DRC_ADDRESS | DRC_DWARFv3 | DRC_FLAG | DRC_REFERENCE | DRC_STRING;
+ case 0x0057: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0058: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0059: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005a: return DRC_DWARFv3 | DRC_STRING;
+ case 0x005b: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005c: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005d: return DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x005e: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005f: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0060: return DRC_DWARFv3 | DRC_STRING;
+ case 0x0061: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0062: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0063: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0064: return DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0065: return DRC_0x65 | DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0066: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0067: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0068: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x2000: return 0;
+ case 0x3fff: return 0;
+ case 0x2001: return DRC_VENDOR_MIPS;
+ case 0x2002: return DRC_VENDOR_MIPS;
+ case 0x2003: return DRC_VENDOR_MIPS;
+ case 0x2004: return DRC_VENDOR_MIPS;
+ case 0x2005: return DRC_VENDOR_MIPS;
+ case 0x2006: return DRC_VENDOR_MIPS;
+ case 0x2007: return DRC_STRING | DRC_VENDOR_MIPS;
+ case 0x2008: return DRC_VENDOR_MIPS;
+ case 0x2009: return DRC_VENDOR_MIPS;
+ case 0x200a: return DRC_VENDOR_MIPS;
+ case 0x200b: return DRC_VENDOR_MIPS;
+ default: return 0;
+ }
+}
+
+/* [7.5.4] Figure 19 "Attribute form encodings" (pp. 133-134) in DWARFv3 draft 8 */
+
+const char *
+DW_FORM_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return DW_FORM_PREFIX "addr";
+ case 0x03: return DW_FORM_PREFIX "block2";
+ case 0x04: return DW_FORM_PREFIX "block4";
+ case 0x05: return DW_FORM_PREFIX "data2";
+ case 0x06: return DW_FORM_PREFIX "data4";
+ case 0x07: return DW_FORM_PREFIX "data8";
+ case 0x08: return DW_FORM_PREFIX "string";
+ case 0x09: return DW_FORM_PREFIX "block";
+ case 0x0a: return DW_FORM_PREFIX "block1";
+ case 0x0b: return DW_FORM_PREFIX "data1";
+ case 0x0c: return DW_FORM_PREFIX "flag";
+ case 0x0d: return DW_FORM_PREFIX "sdata";
+ case 0x0e: return DW_FORM_PREFIX "strp";
+ case 0x0f: return DW_FORM_PREFIX "udata";
+ case 0x10: return DW_FORM_PREFIX "ref_addr";
+ case 0x11: return DW_FORM_PREFIX "ref1";
+ case 0x12: return DW_FORM_PREFIX "ref2";
+ case 0x13: return DW_FORM_PREFIX "ref4";
+ case 0x14: return DW_FORM_PREFIX "ref8";
+ case 0x15: return DW_FORM_PREFIX "ref_udata";
+ case 0x16: return DW_FORM_PREFIX "indirect";
+// case DW_FORM_APPLE_db_str: return DW_FORM_PREFIX "APPLE_db_str";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_FORM constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_FORM_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "addr";
+ case 0x03: return "block2";
+ case 0x04: return "block4";
+ case 0x05: return "data2";
+ case 0x06: return "data4";
+ case 0x07: return "data8";
+ case 0x08: return "string";
+ case 0x09: return "block";
+ case 0x0a: return "block1";
+ case 0x0b: return "data1";
+ case 0x0c: return "flag";
+ case 0x0d: return "sdata";
+ case 0x0e: return "strp";
+ case 0x0f: return "udata";
+ case 0x10: return "ref addr";
+ case 0x11: return "ref1";
+ case 0x12: return "ref2";
+ case 0x13: return "ref4";
+ case 0x14: return "ref8";
+ case 0x15: return "ref udata";
+ case 0x16: return "indirect";
+// case DW_FORM_APPLE_db_str: return "repository str";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_FORM constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_FORM_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return DRC_ADDRESS;
+ case 0x03: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x04: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x05: return DRC_CONSTANT;
+ case 0x06: return DRC_CONSTANT | DRC_LINEPTR | DRC_LOCLISTPTR | DRC_MACPTR | DRC_RANGELISTPTR;
+ case 0x07: return DRC_CONSTANT | DRC_LINEPTR | DRC_LOCLISTPTR | DRC_MACPTR | DRC_RANGELISTPTR;
+ case 0x08: return DRC_STRING;
+ case 0x09: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x0a: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x0b: return DRC_CONSTANT;
+ case 0x0c: return DRC_FLAG;
+ case 0x0d: return DRC_CONSTANT;
+ case 0x0e: return DRC_STRING;
+ case 0x0f: return DRC_CONSTANT;
+ case 0x10: return DRC_REFERENCE;
+ case 0x11: return DRC_REFERENCE;
+ case 0x12: return DRC_REFERENCE;
+ case 0x13: return DRC_REFERENCE;
+ case 0x14: return DRC_REFERENCE;
+ case 0x15: return DRC_REFERENCE;
+ case 0x16: return DRC_INDIRECT_SPECIAL;
+ default: return 0;
+ }
+}
+
+/* [7.7.1] Figure 22 "DWARF operation encodings" (pp. 136-139) in DWARFv3 draft 8 */
+
+const char *
+DW_OP_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x03: return "DW_OP_addr";
+ case 0x06: return "DW_OP_deref";
+ case 0x08: return "DW_OP_const1u";
+ case 0x09: return "DW_OP_const1s";
+ case 0x0a: return "DW_OP_const2u";
+ case 0x0b: return "DW_OP_const2s";
+ case 0x0c: return "DW_OP_const4u";
+ case 0x0d: return "DW_OP_const4s";
+ case 0x0e: return "DW_OP_const8u";
+ case 0x0f: return "DW_OP_const8s";
+ case 0x10: return "DW_OP_constu";
+ case 0x11: return "DW_OP_consts";
+ case 0x12: return "DW_OP_dup";
+ case 0x13: return "DW_OP_drop";
+ case 0x14: return "DW_OP_over";
+ case 0x15: return "DW_OP_pick";
+ case 0x16: return "DW_OP_swap";
+ case 0x17: return "DW_OP_rot";
+ case 0x18: return "DW_OP_xderef";
+ case 0x19: return "DW_OP_abs";
+ case 0x1a: return "DW_OP_and";
+ case 0x1b: return "DW_OP_div";
+ case 0x1c: return "DW_OP_minus";
+ case 0x1d: return "DW_OP_mod";
+ case 0x1e: return "DW_OP_mul";
+ case 0x1f: return "DW_OP_neg";
+ case 0x20: return "DW_OP_not";
+ case 0x21: return "DW_OP_or";
+ case 0x22: return "DW_OP_plus";
+ case 0x23: return "DW_OP_plus_uconst";
+ case 0x24: return "DW_OP_shl";
+ case 0x25: return "DW_OP_shr";
+ case 0x26: return "DW_OP_shra";
+ case 0x27: return "DW_OP_xor";
+ case 0x2f: return "DW_OP_skip";
+ case 0x28: return "DW_OP_bra";
+ case 0x29: return "DW_OP_eq";
+ case 0x2a: return "DW_OP_ge";
+ case 0x2b: return "DW_OP_gt";
+ case 0x2c: return "DW_OP_le";
+ case 0x2d: return "DW_OP_lt";
+ case 0x2e: return "DW_OP_ne";
+ case 0x30: return "DW_OP_lit0";
+ case 0x31: return "DW_OP_lit1";
+ case 0x32: return "DW_OP_lit2";
+ case 0x33: return "DW_OP_lit3";
+ case 0x34: return "DW_OP_lit4";
+ case 0x35: return "DW_OP_lit5";
+ case 0x36: return "DW_OP_lit6";
+ case 0x37: return "DW_OP_lit7";
+ case 0x38: return "DW_OP_lit8";
+ case 0x39: return "DW_OP_lit9";
+ case 0x3a: return "DW_OP_lit10";
+ case 0x3b: return "DW_OP_lit11";
+ case 0x3c: return "DW_OP_lit12";
+ case 0x3d: return "DW_OP_lit13";
+ case 0x3e: return "DW_OP_lit14";
+ case 0x3f: return "DW_OP_lit15";
+ case 0x40: return "DW_OP_lit16";
+ case 0x41: return "DW_OP_lit17";
+ case 0x42: return "DW_OP_lit18";
+ case 0x43: return "DW_OP_lit19";
+ case 0x44: return "DW_OP_lit20";
+ case 0x45: return "DW_OP_lit21";
+ case 0x46: return "DW_OP_lit22";
+ case 0x47: return "DW_OP_lit23";
+ case 0x48: return "DW_OP_lit24";
+ case 0x49: return "DW_OP_lit25";
+ case 0x4a: return "DW_OP_lit26";
+ case 0x4b: return "DW_OP_lit27";
+ case 0x4c: return "DW_OP_lit28";
+ case 0x4d: return "DW_OP_lit29";
+ case 0x4e: return "DW_OP_lit30";
+ case 0x4f: return "DW_OP_lit31";
+ case 0x50: return "DW_OP_reg0";
+ case 0x51: return "DW_OP_reg1";
+ case 0x52: return "DW_OP_reg2";
+ case 0x53: return "DW_OP_reg3";
+ case 0x54: return "DW_OP_reg4";
+ case 0x55: return "DW_OP_reg5";
+ case 0x56: return "DW_OP_reg6";
+ case 0x57: return "DW_OP_reg7";
+ case 0x58: return "DW_OP_reg8";
+ case 0x59: return "DW_OP_reg9";
+ case 0x5a: return "DW_OP_reg10";
+ case 0x5b: return "DW_OP_reg11";
+ case 0x5c: return "DW_OP_reg12";
+ case 0x5d: return "DW_OP_reg13";
+ case 0x5e: return "DW_OP_reg14";
+ case 0x5f: return "DW_OP_reg15";
+ case 0x60: return "DW_OP_reg16";
+ case 0x61: return "DW_OP_reg17";
+ case 0x62: return "DW_OP_reg18";
+ case 0x63: return "DW_OP_reg19";
+ case 0x64: return "DW_OP_reg20";
+ case 0x65: return "DW_OP_reg21";
+ case 0x66: return "DW_OP_reg22";
+ case 0x67: return "DW_OP_reg23";
+ case 0x68: return "DW_OP_reg24";
+ case 0x69: return "DW_OP_reg25";
+ case 0x6a: return "DW_OP_reg26";
+ case 0x6b: return "DW_OP_reg27";
+ case 0x6c: return "DW_OP_reg28";
+ case 0x6d: return "DW_OP_reg29";
+ case 0x6e: return "DW_OP_reg30";
+ case 0x6f: return "DW_OP_reg31";
+ case 0x70: return "DW_OP_breg0";
+ case 0x71: return "DW_OP_breg1";
+ case 0x72: return "DW_OP_breg2";
+ case 0x73: return "DW_OP_breg3";
+ case 0x74: return "DW_OP_breg4";
+ case 0x75: return "DW_OP_breg5";
+ case 0x76: return "DW_OP_breg6";
+ case 0x77: return "DW_OP_breg7";
+ case 0x78: return "DW_OP_breg8";
+ case 0x79: return "DW_OP_breg9";
+ case 0x7a: return "DW_OP_breg10";
+ case 0x7b: return "DW_OP_breg11";
+ case 0x7c: return "DW_OP_breg12";
+ case 0x7d: return "DW_OP_breg13";
+ case 0x7e: return "DW_OP_breg14";
+ case 0x7f: return "DW_OP_breg15";
+ case 0x80: return "DW_OP_breg16";
+ case 0x81: return "DW_OP_breg17";
+ case 0x82: return "DW_OP_breg18";
+ case 0x83: return "DW_OP_breg19";
+ case 0x84: return "DW_OP_breg20";
+ case 0x85: return "DW_OP_breg21";
+ case 0x86: return "DW_OP_breg22";
+ case 0x87: return "DW_OP_breg23";
+ case 0x88: return "DW_OP_breg24";
+ case 0x89: return "DW_OP_breg25";
+ case 0x8a: return "DW_OP_breg26";
+ case 0x8b: return "DW_OP_breg27";
+ case 0x8c: return "DW_OP_breg28";
+ case 0x8d: return "DW_OP_breg29";
+ case 0x8e: return "DW_OP_breg30";
+ case 0x8f: return "DW_OP_breg31";
+ case 0x90: return "DW_OP_regx";
+ case 0x91: return "DW_OP_fbreg";
+ case 0x92: return "DW_OP_bregx";
+ case 0x93: return "DW_OP_piece";
+ case 0x94: return "DW_OP_deref_size";
+ case 0x95: return "DW_OP_xderef_size";
+ case 0x96: return "DW_OP_nop";
+ case 0x97: return "DW_OP_push_object_address";
+ case 0x98: return "DW_OP_call2";
+ case 0x99: return "DW_OP_call4";
+ case 0x9a: return "DW_OP_call_ref";
+ case 0xf0: return "DW_OP_APPLE_uninit";
+ case 0xe0: return "DW_OP_lo_user";
+ case 0xff: return "DW_OP_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_OP_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x03: return "addr";
+ case 0x06: return "deref";
+ case 0x08: return "const1u";
+ case 0x09: return "const1s";
+ case 0x0a: return "const2u";
+ case 0x0b: return "const2s";
+ case 0x0c: return "const4u";
+ case 0x0d: return "const4s";
+ case 0x0e: return "const8u";
+ case 0x0f: return "const8s";
+ case 0x10: return "constu";
+ case 0x11: return "consts";
+ case 0x12: return "dup";
+ case 0x13: return "drop";
+ case 0x14: return "over";
+ case 0x15: return "pick";
+ case 0x16: return "swap";
+ case 0x17: return "rot";
+ case 0x18: return "xderef";
+ case 0x19: return "abs";
+ case 0x1a: return "and";
+ case 0x1b: return "div";
+ case 0x1c: return "minus";
+ case 0x1d: return "mod";
+ case 0x1e: return "mul";
+ case 0x1f: return "neg";
+ case 0x20: return "not";
+ case 0x21: return "or";
+ case 0x22: return "plus";
+ case 0x23: return "plus uconst";
+ case 0x24: return "shl";
+ case 0x25: return "shr";
+ case 0x26: return "shra";
+ case 0x27: return "xor";
+ case 0x2f: return "skip";
+ case 0x28: return "bra";
+ case 0x29: return "eq";
+ case 0x2a: return "ge";
+ case 0x2b: return "gt";
+ case 0x2c: return "le";
+ case 0x2d: return "lt";
+ case 0x2e: return "ne";
+ case 0x30: return "lit0";
+ case 0x31: return "lit1";
+ case 0x32: return "lit2";
+ case 0x33: return "lit3";
+ case 0x34: return "lit4";
+ case 0x35: return "lit5";
+ case 0x36: return "lit6";
+ case 0x37: return "lit7";
+ case 0x38: return "lit8";
+ case 0x39: return "lit9";
+ case 0x3a: return "lit10";
+ case 0x3b: return "lit11";
+ case 0x3c: return "lit12";
+ case 0x3d: return "lit13";
+ case 0x3e: return "lit14";
+ case 0x3f: return "lit15";
+ case 0x40: return "lit16";
+ case 0x41: return "lit17";
+ case 0x42: return "lit18";
+ case 0x43: return "lit19";
+ case 0x44: return "lit20";
+ case 0x45: return "lit21";
+ case 0x46: return "lit22";
+ case 0x47: return "lit23";
+ case 0x48: return "lit24";
+ case 0x49: return "lit25";
+ case 0x4a: return "lit26";
+ case 0x4b: return "lit27";
+ case 0x4c: return "lit28";
+ case 0x4d: return "lit29";
+ case 0x4e: return "lit30";
+ case 0x4f: return "lit31";
+ case 0x50: return "reg0";
+ case 0x51: return "reg1";
+ case 0x52: return "reg2";
+ case 0x53: return "reg3";
+ case 0x54: return "reg4";
+ case 0x55: return "reg5";
+ case 0x56: return "reg6";
+ case 0x57: return "reg7";
+ case 0x58: return "reg8";
+ case 0x59: return "reg9";
+ case 0x5a: return "reg10";
+ case 0x5b: return "reg11";
+ case 0x5c: return "reg12";
+ case 0x5d: return "reg13";
+ case 0x5e: return "reg14";
+ case 0x5f: return "reg15";
+ case 0x60: return "reg16";
+ case 0x61: return "reg17";
+ case 0x62: return "reg18";
+ case 0x63: return "reg19";
+ case 0x64: return "reg20";
+ case 0x65: return "reg21";
+ case 0x66: return "reg22";
+ case 0x67: return "reg23";
+ case 0x68: return "reg24";
+ case 0x69: return "reg25";
+ case 0x6a: return "reg26";
+ case 0x6b: return "reg27";
+ case 0x6c: return "reg28";
+ case 0x6d: return "reg29";
+ case 0x6e: return "reg30";
+ case 0x6f: return "reg31";
+ case 0x70: return "breg0";
+ case 0x71: return "breg1";
+ case 0x72: return "breg2";
+ case 0x73: return "breg3";
+ case 0x74: return "breg4";
+ case 0x75: return "breg5";
+ case 0x76: return "breg6";
+ case 0x77: return "breg7";
+ case 0x78: return "breg8";
+ case 0x79: return "breg9";
+ case 0x7a: return "breg10";
+ case 0x7b: return "breg11";
+ case 0x7c: return "breg12";
+ case 0x7d: return "breg13";
+ case 0x7e: return "breg14";
+ case 0x7f: return "breg15";
+ case 0x80: return "breg16";
+ case 0x81: return "breg17";
+ case 0x82: return "breg18";
+ case 0x83: return "breg19";
+ case 0x84: return "breg20";
+ case 0x85: return "breg21";
+ case 0x86: return "breg22";
+ case 0x87: return "breg23";
+ case 0x88: return "breg24";
+ case 0x89: return "breg25";
+ case 0x8a: return "breg26";
+ case 0x8b: return "breg27";
+ case 0x8c: return "breg28";
+ case 0x8d: return "breg29";
+ case 0x8e: return "breg30";
+ case 0x8f: return "breg31";
+ case 0x90: return "regx";
+ case 0x91: return "fbreg";
+ case 0x92: return "bregx";
+ case 0x93: return "piece";
+ case 0x94: return "deref size";
+ case 0x95: return "xderef size";
+ case 0x96: return "nop";
+ case 0x97: return "push object address";
+ case 0x98: return "call2";
+ case 0x99: return "call4";
+ case 0x9a: return "call ref";
+ case 0xf0: return "uninitialized";
+ case 0xe0: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_OP_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x03: return DRC_ONEOPERAND;
+ case 0x06: return DRC_ZEROOPERANDS;
+ case 0x08: return DRC_ONEOPERAND;
+ case 0x09: return DRC_ONEOPERAND;
+ case 0x0a: return DRC_ONEOPERAND;
+ case 0x0b: return DRC_ONEOPERAND;
+ case 0x0c: return DRC_ONEOPERAND;
+ case 0x0d: return DRC_ONEOPERAND;
+ case 0x0e: return DRC_ONEOPERAND;
+ case 0x0f: return DRC_ONEOPERAND;
+ case 0x10: return DRC_ONEOPERAND;
+ case 0x11: return DRC_ONEOPERAND;
+ case 0x12: return DRC_ZEROOPERANDS;
+ case 0x13: return DRC_ZEROOPERANDS;
+ case 0x14: return DRC_ZEROOPERANDS;
+ case 0x15: return DRC_ONEOPERAND;
+ case 0x16: return DRC_ZEROOPERANDS;
+ case 0x17: return DRC_ZEROOPERANDS;
+ case 0x18: return DRC_ZEROOPERANDS;
+ case 0x19: return DRC_ZEROOPERANDS;
+ case 0x1a: return DRC_ZEROOPERANDS;
+ case 0x1b: return DRC_ZEROOPERANDS;
+ case 0x1c: return DRC_ZEROOPERANDS;
+ case 0x1d: return DRC_ZEROOPERANDS;
+ case 0x1e: return DRC_ZEROOPERANDS;
+ case 0x1f: return DRC_ZEROOPERANDS;
+ case 0x20: return DRC_ZEROOPERANDS;
+ case 0x21: return DRC_ZEROOPERANDS;
+ case 0x22: return DRC_ZEROOPERANDS;
+ case 0x23: return DRC_ONEOPERAND;
+ case 0x24: return DRC_ZEROOPERANDS;
+ case 0x25: return DRC_ZEROOPERANDS;
+ case 0x26: return DRC_ZEROOPERANDS;
+ case 0x27: return DRC_ZEROOPERANDS;
+ case 0x2f: return DRC_ONEOPERAND;
+ case 0x28: return DRC_ONEOPERAND;
+ case 0x29: return DRC_ZEROOPERANDS;
+ case 0x2a: return DRC_ZEROOPERANDS;
+ case 0x2b: return DRC_ZEROOPERANDS;
+ case 0x2c: return DRC_ZEROOPERANDS;
+ case 0x2d: return DRC_ZEROOPERANDS;
+ case 0x2e: return DRC_ZEROOPERANDS;
+ case 0x30: return DRC_ZEROOPERANDS;
+ case 0x31: return DRC_ZEROOPERANDS;
+ case 0x32: return DRC_ZEROOPERANDS;
+ case 0x33: return DRC_ZEROOPERANDS;
+ case 0x34: return DRC_ZEROOPERANDS;
+ case 0x35: return DRC_ZEROOPERANDS;
+ case 0x36: return DRC_ZEROOPERANDS;
+ case 0x37: return DRC_ZEROOPERANDS;
+ case 0x38: return DRC_ZEROOPERANDS;
+ case 0x39: return DRC_ZEROOPERANDS;
+ case 0x3a: return DRC_ZEROOPERANDS;
+ case 0x3b: return DRC_ZEROOPERANDS;
+ case 0x3c: return DRC_ZEROOPERANDS;
+ case 0x3d: return DRC_ZEROOPERANDS;
+ case 0x3e: return DRC_ZEROOPERANDS;
+ case 0x3f: return DRC_ZEROOPERANDS;
+ case 0x40: return DRC_ZEROOPERANDS;
+ case 0x41: return DRC_ZEROOPERANDS;
+ case 0x42: return DRC_ZEROOPERANDS;
+ case 0x43: return DRC_ZEROOPERANDS;
+ case 0x44: return DRC_ZEROOPERANDS;
+ case 0x45: return DRC_ZEROOPERANDS;
+ case 0x46: return DRC_ZEROOPERANDS;
+ case 0x47: return DRC_ZEROOPERANDS;
+ case 0x48: return DRC_ZEROOPERANDS;
+ case 0x49: return DRC_ZEROOPERANDS;
+ case 0x4a: return DRC_ZEROOPERANDS;
+ case 0x4b: return DRC_ZEROOPERANDS;
+ case 0x4c: return DRC_ZEROOPERANDS;
+ case 0x4d: return DRC_ZEROOPERANDS;
+ case 0x4e: return DRC_ZEROOPERANDS;
+ case 0x4f: return DRC_ZEROOPERANDS;
+ case 0x50: return DRC_ZEROOPERANDS;
+ case 0x51: return DRC_ZEROOPERANDS;
+ case 0x52: return DRC_ZEROOPERANDS;
+ case 0x53: return DRC_ZEROOPERANDS;
+ case 0x54: return DRC_ZEROOPERANDS;
+ case 0x55: return DRC_ZEROOPERANDS;
+ case 0x56: return DRC_ZEROOPERANDS;
+ case 0x57: return DRC_ZEROOPERANDS;
+ case 0x58: return DRC_ZEROOPERANDS;
+ case 0x59: return DRC_ZEROOPERANDS;
+ case 0x5a: return DRC_ZEROOPERANDS;
+ case 0x5b: return DRC_ZEROOPERANDS;
+ case 0x5c: return DRC_ZEROOPERANDS;
+ case 0x5d: return DRC_ZEROOPERANDS;
+ case 0x5e: return DRC_ZEROOPERANDS;
+ case 0x5f: return DRC_ZEROOPERANDS;
+ case 0x60: return DRC_ZEROOPERANDS;
+ case 0x61: return DRC_ZEROOPERANDS;
+ case 0x62: return DRC_ZEROOPERANDS;
+ case 0x63: return DRC_ZEROOPERANDS;
+ case 0x64: return DRC_ZEROOPERANDS;
+ case 0x65: return DRC_ZEROOPERANDS;
+ case 0x66: return DRC_ZEROOPERANDS;
+ case 0x67: return DRC_ZEROOPERANDS;
+ case 0x68: return DRC_ZEROOPERANDS;
+ case 0x69: return DRC_ZEROOPERANDS;
+ case 0x6a: return DRC_ZEROOPERANDS;
+ case 0x6b: return DRC_ZEROOPERANDS;
+ case 0x6c: return DRC_ZEROOPERANDS;
+ case 0x6d: return DRC_ZEROOPERANDS;
+ case 0x6e: return DRC_ZEROOPERANDS;
+ case 0x6f: return DRC_ZEROOPERANDS;
+ case 0x70: return DRC_ONEOPERAND;
+ case 0x71: return DRC_ONEOPERAND;
+ case 0x72: return DRC_ONEOPERAND;
+ case 0x73: return DRC_ONEOPERAND;
+ case 0x74: return DRC_ONEOPERAND;
+ case 0x75: return DRC_ONEOPERAND;
+ case 0x76: return DRC_ONEOPERAND;
+ case 0x77: return DRC_ONEOPERAND;
+ case 0x78: return DRC_ONEOPERAND;
+ case 0x79: return DRC_ONEOPERAND;
+ case 0x7a: return DRC_ONEOPERAND;
+ case 0x7b: return DRC_ONEOPERAND;
+ case 0x7c: return DRC_ONEOPERAND;
+ case 0x7d: return DRC_ONEOPERAND;
+ case 0x7e: return DRC_ONEOPERAND;
+ case 0x7f: return DRC_ONEOPERAND;
+ case 0x80: return DRC_ONEOPERAND;
+ case 0x81: return DRC_ONEOPERAND;
+ case 0x82: return DRC_ONEOPERAND;
+ case 0x83: return DRC_ONEOPERAND;
+ case 0x84: return DRC_ONEOPERAND;
+ case 0x85: return DRC_ONEOPERAND;
+ case 0x86: return DRC_ONEOPERAND;
+ case 0x87: return DRC_ONEOPERAND;
+ case 0x88: return DRC_ONEOPERAND;
+ case 0x89: return DRC_ONEOPERAND;
+ case 0x8a: return DRC_ONEOPERAND;
+ case 0x8b: return DRC_ONEOPERAND;
+ case 0x8c: return DRC_ONEOPERAND;
+ case 0x8d: return DRC_ONEOPERAND;
+ case 0x8e: return DRC_ONEOPERAND;
+ case 0x8f: return DRC_ONEOPERAND;
+ case 0x90: return DRC_ONEOPERAND;
+ case 0x91: return DRC_ONEOPERAND;
+ case 0x92: return DRC_TWOOPERANDS;
+ case 0x93: return DRC_ONEOPERAND;
+ case 0x94: return DRC_ONEOPERAND;
+ case 0x95: return DRC_ONEOPERAND;
+ case 0x96: return DRC_ZEROOPERANDS;
+ case 0x97: return DRC_DWARFv3 | DRC_ZEROOPERANDS;
+ case 0x98: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0x99: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0x9a: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0xf0: return DRC_ZEROOPERANDS; /* DW_OP_APPLE_uninit */
+ case 0xe0: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.8] Figure 23 "Base type encoding values" (pp. 140-141) in DWARFv3 draft 8 */
+
+const char *
+DW_ATE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_ATE_address";
+ case 0x02: return "DW_ATE_boolean";
+ case 0x03: return "DW_ATE_complex_float";
+ case 0x04: return "DW_ATE_float";
+ case 0x05: return "DW_ATE_signed";
+ case 0x06: return "DW_ATE_signed_char";
+ case 0x07: return "DW_ATE_unsigned";
+ case 0x08: return "DW_ATE_unsigned_char";
+ case 0x09: return "DW_ATE_imaginary_float";
+ case 0x80: return "DW_ATE_lo_user";
+ case 0xff: return "DW_ATE_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ATE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ATE_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "address";
+ case 0x02: return "boolean";
+ case 0x03: return "complex float";
+ case 0x04: return "float";
+ case 0x05: return "signed";
+ case 0x06: return "signed char";
+ case 0x07: return "unsigned";
+ case 0x08: return "unsigned char";
+ case 0x09: return "imaginary float";
+ case 0x80: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ATE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ATE_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x04: return 0;
+ case 0x05: return 0;
+ case 0x06: return 0;
+ case 0x07: return 0;
+ case 0x08: return 0;
+ case 0x09: return DRC_DWARFv3;
+ case 0x80: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.9] Figure 24 "Accessibility encodings" (p. 141) in DWARFv3 draft 8 */
+
+const char *
+DW_ACCESS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "DW_ACCESS_public";
+ case 0x2: return "DW_ACCESS_protected";
+ case 0x3: return "DW_ACCESS_private";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ACCESS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ACCESS_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "public";
+ case 0x2: return "protected";
+ case 0x3: return "private";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ACCESS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ACCESS_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.10] Figure 25 "Visibility encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *
+DW_VIS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "DW_VIS_local";
+ case 0x2: return "DW_VIS_exported";
+ case 0x3: return "DW_VIS_qualified";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_VIS_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "local";
+ case 0x2: return "exported";
+ case 0x3: return "qualified";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_VIS_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.11] Figure 26 "Virtuality encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *
+DW_VIRTUALITY_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_VIRTUALITY_none";
+ case 0x1: return "DW_VIRTUALITY_virtual";
+ case 0x2: return "DW_VIRTUALITY_pure_virtual";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_VIRTUALITY_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "none";
+ case 0x1: return "virtual";
+ case 0x2: return "pure virtual";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_VIRTUALITY_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ case 0x2: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.12] Figure 27 "Language encodings" (p. 143) in DWARFv3 draft 8 */
+
+const char *
+DW_LANG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "DW_LANG_C89";
+ case 0x0002: return "DW_LANG_C";
+ case 0x0003: return "DW_LANG_Ada83";
+ case 0x0004: return "DW_LANG_C_plus_plus";
+ case 0x0005: return "DW_LANG_Cobol74";
+ case 0x0006: return "DW_LANG_Cobol85";
+ case 0x0007: return "DW_LANG_Fortran77";
+ case 0x0008: return "DW_LANG_Fortran90";
+ case 0x0009: return "DW_LANG_Pascal83";
+ case 0x000a: return "DW_LANG_Modula2";
+ case 0x000b: return "DW_LANG_Java";
+ case 0x000c: return "DW_LANG_C99";
+ case 0x000d: return "DW_LANG_Ada95";
+ case 0x000e: return "DW_LANG_Fortran95";
+ case 0x000f: return "DW_LANG_PLI";
+ case 0x0010: return "DW_LANG_ObjC";
+ case 0x0011: return "DW_LANG_ObjC_plus_plus";
+ case 0x0012: return "DW_LANG_UPC";
+ case 0x0013: return "DW_LANG_D";
+ case 0x8000: return "DW_LANG_lo_user";
+ case 0x8001: return "DW_LANG_Mips_Assembler";
+ case 0x8765: return "DW_LANG_Upc";
+ case 0xffff: return "DW_LANG_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LANG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_LANG_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "C89";
+ case 0x0002: return "C";
+ case 0x0003: return "Ada83";
+ case 0x0004: return "C++";
+ case 0x0005: return "Cobol74";
+ case 0x0006: return "Cobol85";
+ case 0x0007: return "Fortran77";
+ case 0x0008: return "Fortran90";
+ case 0x0009: return "Pascal83";
+ case 0x000a: return "Modula2";
+ case 0x000b: return "Java";
+ case 0x000c: return "C99";
+ case 0x000d: return "Ada95";
+ case 0x000e: return "Fortran95";
+ case 0x000f: return "PLI";
+ case 0x0010: return "Objective C";
+ case 0x0011: return "Objective C++";
+ case 0x0012: return "UPC";
+ case 0x0013: return "D";
+ case 0x8000: return "lo user";
+ case 0x8001: return "MIPS Assembler";
+ case 0x8765: return "UPC";
+ case 0xffff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LANG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_LANG_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0001: return 0;
+ case 0x0002: return 0;
+ case 0x0003: return 0;
+ case 0x0004: return 0;
+ case 0x0005: return 0;
+ case 0x0006: return 0;
+ case 0x0007: return 0;
+ case 0x0008: return 0;
+ case 0x0009: return 0;
+ case 0x000a: return 0;
+ case 0x000b: return DRC_DWARFv3;
+ case 0x000c: return DRC_DWARFv3;
+ case 0x000d: return DRC_DWARFv3;
+ case 0x000e: return DRC_DWARFv3;
+ case 0x000f: return DRC_DWARFv3;
+ case 0x0010: return DRC_DWARFv3;
+ case 0x0011: return DRC_DWARFv3;
+ case 0x0012: return DRC_DWARFv3;
+ case 0x0013: return DRC_DWARFv3;
+ case 0x8000: return 0;
+ case 0x8001: return 0;
+ case 0x8765: return 0;
+ case 0xffff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.13], "Address Class Encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *
+DW_ADDR_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_ADDR_none";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ADDR constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ADDR_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "none";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ADDR constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ADDR_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.14] Figure 28 "Identifier case encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *
+DW_ID_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_ID_case_sensitive";
+ case 0x1: return "DW_ID_up_case";
+ case 0x2: return "DW_ID_down_case";
+ case 0x3: return "DW_ID_case_insensitive";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ID constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ID_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "case sensitive";
+ case 0x1: return "up case";
+ case 0x2: return "down case";
+ case 0x3: return "case insensitive";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ID constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ID_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.15] Figure 29 "Calling convention encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *
+DW_CC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_CC_normal";
+ case 0x02: return "DW_CC_program";
+ case 0x03: return "DW_CC_nocall";
+ case 0x40: return "DW_CC_lo_user";
+ case 0xff: return "DW_CC_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_CC_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "normal";
+ case 0x02: return "program";
+ case 0x03: return "nocall";
+ case 0x40: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_CC_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x40: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.16] Figure 30 "Inline encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *
+DW_INL_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_INL_not_inlined";
+ case 0x1: return "DW_INL_inlined";
+ case 0x2: return "DW_INL_declared_not_inlined";
+ case 0x3: return "DW_INL_declared_inlined";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_INL constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_INL_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "not inlined";
+ case 0x1: return "inlined";
+ case 0x2: return "declared not inlined";
+ case 0x3: return "declared inlined";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_INL constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_INL_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.17] Figure 31 "Ordering encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *
+DW_ORD_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_ORD_row_major";
+ case 0x1: return "DW_ORD_col_major";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ORD constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ORD_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "row major";
+ case 0x1: return "col major";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ORD constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ORD_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.18] Figure 32 "Discriminant descriptor encodings" (p. 146) in DWARFv3 draft 8 */
+
+const char *
+DW_DSC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_DSC_label";
+ case 0x1: return "DW_DSC_range";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_DSC_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "label";
+ case 0x1: return "range";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_DSC_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.21] Figure 33 "Line Number Standard Opcode Encodings" (pp. 148-149) in DWARFv3 draft 8 */
+
+const char *
+DW_LNS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "DW_LNS_copy";
+ case 0x2: return "DW_LNS_advance_pc";
+ case 0x3: return "DW_LNS_advance_line";
+ case 0x4: return "DW_LNS_set_file";
+ case 0x5: return "DW_LNS_set_column";
+ case 0x6: return "DW_LNS_negate_stmt";
+ case 0x7: return "DW_LNS_set_basic_block";
+ case 0x8: return "DW_LNS_const_add_pc";
+ case 0x9: return "DW_LNS_fixed_advance_pc";
+ case 0xa: return "DW_LNS_set_prologue_end";
+ case 0xb: return "DW_LNS_set_epilogue_begin";
+ case 0xc: return "DW_LNS_set_isa";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_LNS_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "copy";
+ case 0x2: return "advance pc";
+ case 0x3: return "advance line";
+ case 0x4: return "set file";
+ case 0x5: return "set column";
+ case 0x6: return "negate stmt";
+ case 0x7: return "set basic block";
+ case 0x8: return "const add pc";
+ case 0x9: return "fixed advance pc";
+ case 0xa: return "set prologue end";
+ case 0xb: return "set epilogue begin";
+ case 0xc: return "set isa";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_LNS_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ case 0x4: return 0;
+ case 0x5: return 0;
+ case 0x6: return 0;
+ case 0x7: return 0;
+ case 0x8: return 0;
+ case 0x9: return 0;
+ case 0xa: return DRC_DWARFv3;
+ case 0xb: return DRC_DWARFv3;
+ case 0xc: return DRC_DWARFv3;
+ default: return 0;
+ }
+}
+
+/* [7.21] Figure 34 "Line Number Extended Opcode Encodings" (p. 149) in DWARFv3 draft 8 */
+
+const char *
+DW_LNE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_LNE_end_sequence";
+ case 0x02: return "DW_LNE_set_address";
+ case 0x03: return "DW_LNE_define_file";
+ case 0x80: return "DW_LNE_lo_user";
+ case 0xff: return "DW_LNE_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_LNE_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "end sequence";
+ case 0x02: return "set address";
+ case 0x03: return "define file";
+ case 0x80: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_LNE_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x80: return DRC_DWARFv3;
+ case 0xff: return DRC_DWARFv3;
+ default: return 0;
+ }
+}
+
+/* [7.22] Figure 35 "Macinfo Type Encodings" (p. 150) in DWARFv3 draft 8 */
+
+const char *
+DW_MACINFO_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_MACINFO_define";
+ case 0x02: return "DW_MACINFO_undef";
+ case 0x03: return "DW_MACINFO_start_file";
+ case 0x04: return "DW_MACINFO_end_file";
+ case 0xff: return "DW_MACINFO_vendor_ext";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_MACINFO constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_MACINFO_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "define";
+ case 0x02: return "undef";
+ case 0x03: return "start file";
+ case 0x04: return "end file";
+ case 0xff: return "vendor ext";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_MACINFO constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_MACINFO_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x04: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.23] Figure 36 "Call frame instruction encodings" (pp. 151-152) in DWARFv3 draft 8 */
+
+const char *
+DW_CFA_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x40: return "DW_CFA_advance_loc";
+ case 0x80: return "DW_CFA_offset";
+ case 0xc0: return "DW_CFA_restore";
+ case 0x00: return "DW_CFA_nop";
+ case 0x01: return "DW_CFA_set_loc";
+ case 0x02: return "DW_CFA_advance_loc1";
+ case 0x03: return "DW_CFA_advance_loc2";
+ case 0x04: return "DW_CFA_advance_loc4";
+ case 0x05: return "DW_CFA_offset_extended";
+ case 0x06: return "DW_CFA_restore_extended";
+ case 0x07: return "DW_CFA_undefined";
+ case 0x08: return "DW_CFA_same_value";
+ case 0x09: return "DW_CFA_register";
+ case 0x0a: return "DW_CFA_remember_state";
+ case 0x0b: return "DW_CFA_restore_state";
+ case 0x0c: return "DW_CFA_def_cfa";
+ case 0x0d: return "DW_CFA_def_cfa_register";
+ case 0x0e: return "DW_CFA_def_cfa_offset";
+ case 0x0f: return "DW_CFA_def_cfa_expression";
+ case 0x10: return "DW_CFA_expression";
+ case 0x11: return "DW_CFA_offset_extended_sf";
+ case 0x12: return "DW_CFA_def_cfa_sf";
+ case 0x13: return "DW_CFA_def_cfa_offset_sf";
+ case 0x1c: return "DW_CFA_lo_user";
+ case 0x3f: return "DW_CFA_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CFA constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_CFA_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x40: return "advance loc";
+ case 0x80: return "offset";
+ case 0xc0: return "restore";
+ case 0x00: return "nop";
+ case 0x01: return "set loc";
+ case 0x02: return "advance loc1";
+ case 0x03: return "advance loc2";
+ case 0x04: return "advance loc4";
+ case 0x05: return "offset extended";
+ case 0x06: return "restore extended";
+ case 0x07: return "undefined";
+ case 0x08: return "same value";
+ case 0x09: return "register";
+ case 0x0a: return "remember state";
+ case 0x0b: return "restore state";
+ case 0x0c: return "def cfa";
+ case 0x0d: return "def cfa register";
+ case 0x0e: return "def cfa offset";
+ case 0x0f: return "def cfa expression";
+ case 0x10: return "expression";
+ case 0x11: return "offset extended sf";
+ case 0x12: return "def cfa sf";
+ case 0x13: return "def cfa offset sf";
+ case 0x1c: return "lo user";
+ case 0x3f: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CFA constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_CFA_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x40: return DRC_ZEROOPERANDS;
+ case 0x80: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_OFFSET;
+ case 0xc0: return DRC_ZEROOPERANDS;
+ case 0x00: return DRC_ZEROOPERANDS;
+ case 0x01: return DRC_ONEOPERAND | DRC_OPERANDONE_ADDRESS;
+ case 0x02: return DRC_ONEOPERAND | DRC_OPERANDONE_1BYTE_DELTA;
+ case 0x03: return DRC_ONEOPERAND | DRC_OPERANDONE_2BYTE_DELTA;
+ case 0x04: return DRC_ONEOPERAND | DRC_OPERANDONE_4BYTE_DELTA;
+ case 0x05: return DRC_OPERANDTWO_ULEB128_OFFSET | DRC_OPERNADONE_ULEB128_REGISTER | DRC_TWOOPERANDS;
+ case 0x06: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x07: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x08: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x09: return DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_ULEB128_REGISTER | DRC_TWOOPERANDS;
+ case 0x0a: return DRC_ZEROOPERANDS;
+ case 0x0b: return DRC_ZEROOPERANDS;
+ case 0x0c: return DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_ULEB128_OFFSET | DRC_TWOOPERANDS;
+ case 0x0d: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x0e: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_OFFSET;
+ case 0x0f: return DRC_DWARFv3 | DRC_ONEOPERAND | DRC_OPERANDONE_BLOCK;
+ case 0x10: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_BLOCK | DRC_TWOOPERANDS;
+ case 0x11: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_SLEB128_OFFSET | DRC_TWOOPERANDS;
+ case 0x12: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_SLEB128_OFFSET | DRC_TWOOPERANDS;
+ case 0x13: return DRC_DWARFv3 | DRC_ONEOPERAND | DRC_OPERANDONE_SLEB128_OFFSET;
+ case 0x1c: return 0;
+ case 0x3f: return 0;
+ default: return 0;
+ }
+}
+
+/* FSF exception handling Pointer-Encoding constants (CFI augmentation) -- "DW_EH_PE_..." in the FSF sources */
+
+const char *
+DW_GNU_EH_PE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x00: return "DW_GNU_EH_PE_absptr";
+ case 0x01: return "DW_GNU_EH_PE_uleb128";
+ case 0x02: return "DW_GNU_EH_PE_udata2";
+ case 0x03: return "DW_GNU_EH_PE_udata4";
+ case 0x04: return "DW_GNU_EH_PE_udata8";
+ case 0x09: return "DW_GNU_EH_PE_sleb128";
+ case 0x0a: return "DW_GNU_EH_PE_sdata2";
+ case 0x0b: return "DW_GNU_EH_PE_sdata4";
+ case 0x0c: return "DW_GNU_EH_PE_sdata8";
+ case 0x08: return "DW_GNU_EH_PE_signed";
+ case 0x10: return "DW_GNU_EH_PE_pcrel";
+ case 0x20: return "DW_GNU_EH_PE_textrel";
+ case 0x30: return "DW_GNU_EH_PE_datarel";
+ case 0x40: return "DW_GNU_EH_PE_funcrel";
+ case 0x50: return "DW_GNU_EH_PE_aligned";
+ case 0x80: return "DW_GNU_EH_PE_indirect";
+ case 0xff: return "DW_GNU_EH_PE_omit";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_GNU_EH_PE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_GNU_EH_PE_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x00: return "absptr";
+ case 0x01: return "uleb128";
+ case 0x02: return "udata2";
+ case 0x03: return "udata4";
+ case 0x04: return "udata8";
+ case 0x09: return "sleb128";
+ case 0x0a: return "sdata2";
+ case 0x0b: return "sdata4";
+ case 0x0c: return "sdata8";
+ case 0x08: return "signed";
+ case 0x10: return "pcrel";
+ case 0x20: return "textrel";
+ case 0x30: return "datarel";
+ case 0x40: return "funcrel";
+ case 0x50: return "aligned";
+ case 0x80: return "indirect";
+ case 0xff: return "omit";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_GNU_EH_PE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_GNU_EH_PE_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x00: return DRC_VENDOR_GNU;
+ case 0x01: return DRC_VENDOR_GNU;
+ case 0x02: return DRC_VENDOR_GNU;
+ case 0x03: return DRC_VENDOR_GNU;
+ case 0x04: return DRC_VENDOR_GNU;
+ case 0x09: return DRC_VENDOR_GNU;
+ case 0x0a: return DRC_VENDOR_GNU;
+ case 0x0b: return DRC_VENDOR_GNU;
+ case 0x0c: return DRC_VENDOR_GNU;
+ case 0x08: return DRC_VENDOR_GNU;
+ case 0x10: return DRC_VENDOR_GNU;
+ case 0x20: return DRC_VENDOR_GNU;
+ case 0x30: return DRC_VENDOR_GNU;
+ case 0x40: return DRC_VENDOR_GNU;
+ case 0x50: return DRC_VENDOR_GNU;
+ case 0x80: return DRC_VENDOR_GNU;
+ case 0xff: return DRC_VENDOR_GNU;
+ default: return 0;
+ }
+}
+
+bool
+is_type_tag (uint16_t tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_array_type:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_const_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_file_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_set_type:
+ case DW_TAG_shared_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_thrown_type:
+ case DW_TAG_union_type:
+ case DW_TAG_unspecified_type:
+ case DW_TAG_volatile_type:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool
+is_pubtype_tag (uint16_t tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_array_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_file_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_set_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_thrown_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ case DW_TAG_unspecified_type:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+DW_TAG_CategoryEnum
+get_tag_category (uint16_t tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_array_type : return TagCategoryType;
+ case DW_TAG_class_type : return TagCategoryType;
+ case DW_TAG_entry_point : return TagCategoryProgram;
+ case DW_TAG_enumeration_type : return TagCategoryType;
+ case DW_TAG_formal_parameter : return TagCategoryVariable;
+ case DW_TAG_imported_declaration : return TagCategoryProgram;
+ case DW_TAG_label : return TagCategoryProgram;
+ case DW_TAG_lexical_block : return TagCategoryProgram;
+ case DW_TAG_member : return TagCategoryType;
+ case DW_TAG_pointer_type : return TagCategoryType;
+ case DW_TAG_reference_type : return TagCategoryType;
+ case DW_TAG_compile_unit : return TagCategoryProgram;
+ case DW_TAG_string_type : return TagCategoryType;
+ case DW_TAG_structure_type : return TagCategoryType;
+ case DW_TAG_subroutine_type : return TagCategoryType;
+ case DW_TAG_typedef : return TagCategoryType;
+ case DW_TAG_union_type : return TagCategoryType;
+ case DW_TAG_unspecified_parameters : return TagCategoryVariable;
+ case DW_TAG_variant : return TagCategoryType;
+ case DW_TAG_common_block : return TagCategoryProgram;
+ case DW_TAG_common_inclusion : return TagCategoryProgram;
+ case DW_TAG_inheritance : return TagCategoryType;
+ case DW_TAG_inlined_subroutine : return TagCategoryProgram;
+ case DW_TAG_module : return TagCategoryProgram;
+ case DW_TAG_ptr_to_member_type : return TagCategoryType;
+ case DW_TAG_set_type : return TagCategoryType;
+ case DW_TAG_subrange_type : return TagCategoryType;
+ case DW_TAG_with_stmt : return TagCategoryProgram;
+ case DW_TAG_access_declaration : return TagCategoryProgram;
+ case DW_TAG_base_type : return TagCategoryType;
+ case DW_TAG_catch_block : return TagCategoryProgram;
+ case DW_TAG_const_type : return TagCategoryType;
+ case DW_TAG_constant : return TagCategoryVariable;
+ case DW_TAG_enumerator : return TagCategoryType;
+ case DW_TAG_file_type : return TagCategoryType;
+ case DW_TAG_friend : return TagCategoryType;
+ case DW_TAG_namelist : return TagCategoryVariable;
+ case DW_TAG_namelist_item : return TagCategoryVariable;
+ case DW_TAG_packed_type : return TagCategoryType;
+ case DW_TAG_subprogram : return TagCategoryProgram;
+ case DW_TAG_template_type_parameter : return TagCategoryType;
+ case DW_TAG_template_value_parameter : return TagCategoryType;
+ case DW_TAG_thrown_type : return TagCategoryType;
+ case DW_TAG_try_block : return TagCategoryProgram;
+ case DW_TAG_variant_part : return TagCategoryType;
+ case DW_TAG_variable : return TagCategoryVariable;
+ case DW_TAG_volatile_type : return TagCategoryType;
+ case DW_TAG_dwarf_procedure : return TagCategoryProgram;
+ case DW_TAG_restrict_type : return TagCategoryType;
+ case DW_TAG_interface_type : return TagCategoryType;
+ case DW_TAG_namespace : return TagCategoryProgram;
+ case DW_TAG_imported_module : return TagCategoryProgram;
+ case DW_TAG_unspecified_type : return TagCategoryType;
+ case DW_TAG_partial_unit : return TagCategoryProgram;
+ case DW_TAG_imported_unit : return TagCategoryProgram;
+ case DW_TAG_shared_type : return TagCategoryType;
+ default: break;
+ }
+ return TagCategoryProgram;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
new file mode 100644
index 0000000..dafe8a7
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
@@ -0,0 +1,252 @@
+//===-- DWARFDefines.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_DWARFDefines_h_
+#define liblldb_DWARFDefines_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "lldb/Core/dwarf.h"
+
+/* DWARF constants generated on Wed Sep 7 16:41:50 2005 */
+
+typedef uint32_t DRC_class; // Holds DRC_* class bitfields
+
+/* [7.5.4] Figure 16 "Tag Encodings" (pp. 125-127) in DWARFv3 draft 8 */
+
+
+enum DW_TAG_Category
+{
+ TagCategoryVariable,
+ TagCategoryType,
+ TagCategoryProgram,
+ kNumTagCategories
+};
+
+typedef enum DW_TAG_Category DW_TAG_CategoryEnum;
+const char *DW_TAG_value_to_name (uint32_t val);
+const char *DW_TAG_value_to_englishy_name (uint32_t val);
+DRC_class DW_TAG_value_to_class (uint32_t val);
+DW_TAG_CategoryEnum get_tag_category (uint16_t tag);
+#define DW_TAG_MAX_NAME_LENGTH 31
+
+
+/* [7.5.4] Figure 17 "Child determination encodings" (p. 128) in DWARFv3 draft 8 */
+
+const char *DW_CHILDREN_value_to_name (uint8_t val);
+const char *DW_CHILDREN_value_to_englishy_name (uint8_t val);
+DRC_class DW_CHILDREN_value_to_class (uint32_t val);
+#define DW_CHILDREN_MAX_NAME_LENGTH 15
+
+
+/* [7.5.4] Figure 18 "Attribute encodings" (pp. 129-132) in DWARFv3 draft 8 */
+
+
+const char *DW_AT_value_to_name (uint32_t val);
+const char *DW_AT_value_to_englishy_name (uint32_t val);
+DRC_class DW_AT_value_to_class (uint32_t val);
+#define DW_AT_MAX_NAME_LENGTH 34
+
+
+/* [7.5.4] Figure 19 "Attribute form encodings" (pp. 133-134) in DWARFv3 draft 8 */
+
+const char *DW_FORM_value_to_name (uint32_t val);
+const char *DW_FORM_value_to_englishy_name (uint32_t val);
+DRC_class DW_FORM_value_to_class (uint32_t val);
+#define DW_FORM_MAX_NAME_LENGTH 17
+
+
+/* [7.7.1] Figure 22 "DWARF operation encodings" (pp. 136-139) in DWARFv3 draft 8 */
+
+const char *DW_OP_value_to_name (uint32_t val);
+const char *DW_OP_value_to_englishy_name (uint32_t val);
+DRC_class DW_OP_value_to_class (uint32_t val);
+#define DW_OP_MAX_NAME_LENGTH 25
+
+
+/* [7.8] Figure 23 "Base type encoding values" (pp. 140-141) in DWARFv3 draft 8 */
+
+const char *DW_ATE_value_to_name (uint32_t val);
+const char *DW_ATE_value_to_englishy_name (uint32_t val);
+DRC_class DW_ATE_value_to_class (uint32_t val);
+#define DW_ATE_MAX_NAME_LENGTH 22
+
+
+/* [7.9] Figure 24 "Accessibility encodings" (p. 141) in DWARFv3 draft 8 */
+
+const char *DW_ACCESS_value_to_name (uint32_t val);
+const char *DW_ACCESS_value_to_englishy_name (uint32_t val);
+DRC_class DW_ACCESS_value_to_class (uint32_t val);
+#define DW_ACCESS_MAX_NAME_LENGTH 19
+
+
+/* [7.10] Figure 25 "Visibility encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *DW_VIS_value_to_name (uint32_t val);
+const char *DW_VIS_value_to_englishy_name (uint32_t val);
+DRC_class DW_VIS_value_to_class (uint32_t val);
+#define DW_VIS_MAX_NAME_LENGTH 16
+
+
+/* [7.11] Figure 26 "Virtuality encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *DW_VIRTUALITY_value_to_name (uint32_t val);
+const char *DW_VIRTUALITY_value_to_englishy_name (uint32_t val);
+DRC_class DW_VIRTUALITY_value_to_class (uint32_t val);
+#define DW_VIRTUALITY_MAX_NAME_LENGTH 26
+
+
+/* [7.12] Figure 27 "Language encodings" (p. 143) in DWARFv3 draft 8 */
+
+const char *DW_LANG_value_to_name (uint32_t val);
+const char *DW_LANG_value_to_englishy_name (uint32_t val);
+DRC_class DW_LANG_value_to_class (uint32_t val);
+#define DW_LANG_MAX_NAME_LENGTH 19
+
+
+/* [7.13], "Address Class Encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *DW_ADDR_value_to_name (uint32_t val);
+const char *DW_ADDR_value_to_englishy_name (uint32_t val);
+DRC_class DW_ADDR_value_to_class (uint32_t val);
+#define DW_ADDR_MAX_NAME_LENGTH 12
+
+
+/* [7.14] Figure 28 "Identifier case encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *DW_ID_value_to_name (uint32_t val);
+const char *DW_ID_value_to_englishy_name (uint32_t val);
+DRC_class DW_ID_value_to_class (uint32_t val);
+#define DW_ID_MAX_NAME_LENGTH 22
+
+
+/* [7.15] Figure 29 "Calling convention encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *DW_CC_value_to_name (uint32_t val);
+const char *DW_CC_value_to_englishy_name (uint32_t val);
+DRC_class DW_CC_value_to_class (uint32_t val);
+#define DW_CC_MAX_NAME_LENGTH 13
+
+
+/* [7.16] Figure 30 "Inline encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *DW_INL_value_to_name (uint32_t val);
+const char *DW_INL_value_to_englishy_name (uint32_t val);
+DRC_class DW_INL_value_to_class (uint32_t val);
+#define DW_INL_MAX_NAME_LENGTH 27
+
+
+/* [7.17] Figure 31 "Ordering encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *DW_ORD_value_to_name (uint32_t val);
+const char *DW_ORD_value_to_englishy_name (uint32_t val);
+DRC_class DW_ORD_value_to_class (uint32_t val);
+#define DW_ORD_MAX_NAME_LENGTH 16
+
+
+/* [7.18] Figure 32 "Discriminant descriptor encodings" (p. 146) in DWARFv3 draft 8 */
+
+const char *DW_DSC_value_to_name (uint32_t val);
+const char *DW_DSC_value_to_englishy_name (uint32_t val);
+DRC_class DW_DSC_value_to_class (uint32_t val);
+#define DW_DSC_MAX_NAME_LENGTH 12
+
+
+/* [7.21] Figure 33 "Line Number Standard Opcode Encodings" (pp. 148-149) in DWARFv3 draft 8 */
+
+const char *DW_LNS_value_to_name (uint32_t val);
+const char *DW_LNS_value_to_englishy_name (uint32_t val);
+DRC_class DW_LNS_value_to_class (uint32_t val);
+#define DW_LNS_MAX_NAME_LENGTH 25
+
+
+/* [7.21] Figure 34 "Line Number Extended Opcode Encodings" (p. 149) in DWARFv3 draft 8 */
+
+const char *DW_LNE_value_to_name (uint32_t val);
+const char *DW_LNE_value_to_englishy_name (uint32_t val);
+DRC_class DW_LNE_value_to_class (uint32_t val);
+#define DW_LNE_MAX_NAME_LENGTH 19
+
+
+/* [7.22] Figure 35 "Macinfo Type Encodings" (p. 150) in DWARFv3 draft 8 */
+
+const char *DW_MACINFO_value_to_name (uint32_t val);
+const char *DW_MACINFO_value_to_englishy_name (uint32_t val);
+DRC_class DW_MACINFO_value_to_class (uint32_t val);
+#define DW_MACINFO_MAX_NAME_LENGTH 21
+
+
+/* [7.23] Figure 36 "Call frame instruction encodings" (pp. 151-152) in DWARFv3 draft 8 */
+
+const char *DW_CFA_value_to_name (uint32_t val);
+const char *DW_CFA_value_to_englishy_name (uint32_t val);
+DRC_class DW_CFA_value_to_class (uint32_t val);
+#define DW_CFA_MAX_NAME_LENGTH 25
+
+
+/* FSF exception handling Pointer-Encoding constants (CFI augmentation) -- "DW_EH_PE_..." in the FSF sources */
+
+const char *DW_GNU_EH_PE_value_to_name (uint32_t val);
+const char *DW_GNU_EH_PE_value_to_englishy_name (uint32_t val);
+DRC_class DW_GNU_EH_PE_value_to_class (uint32_t val);
+#define DW_GNU_EH_PE_MAX_NAME_LENGTH 21
+
+
+/* These DRC are entirely our own construction,
+ although they are derived from various comments in the DWARF standard.
+ Most of these are not useful to the parser, but the DW_AT and DW_FORM
+ classes should prove to be usable in some fashion. */
+
+#define DRC_0x65 0x1
+#define DRC_ADDRESS 0x2
+#define DRC_BLOCK 0x4
+#define DRC_CONSTANT 0x8
+#define DRC_DWARFv3 0x10
+#define DRC_FLAG 0x20
+#define DRC_INDIRECT_SPECIAL 0x40
+#define DRC_LINEPTR 0x80
+#define DRC_LOCEXPR 0x100
+#define DRC_LOCLISTPTR 0x200
+#define DRC_MACPTR 0x400
+#define DRC_ONEOPERAND 0x800
+#define DRC_OPERANDONE_1BYTE_DELTA 0x1000
+#define DRC_OPERANDONE_2BYTE_DELTA 0x2000
+#define DRC_OPERANDONE_4BYTE_DELTA 0x4000
+#define DRC_OPERANDONE_ADDRESS 0x8000
+#define DRC_OPERANDONE_BLOCK 0x10000
+#define DRC_OPERANDONE_SLEB128_OFFSET 0x20000
+#define DRC_OPERANDONE_ULEB128_OFFSET 0x40000
+#define DRC_OPERANDONE_ULEB128_REGISTER 0x80000
+#define DRC_OPERANDTWO_BLOCK 0x100000
+#define DRC_OPERANDTWO_SLEB128_OFFSET 0x200000
+#define DRC_OPERANDTWO_ULEB128_OFFSET 0x400000
+#define DRC_OPERANDTWO_ULEB128_REGISTER 0x800000
+#define DRC_OPERNADONE_ULEB128_REGISTER 0x1000000
+#define DRC_RANGELISTPTR 0x2000000
+#define DRC_REFERENCE 0x4000000
+#define DRC_STRING 0x8000000
+#define DRC_TWOOPERANDS 0x10000000
+#define DRC_VENDOR_GNU 0x20000000
+#define DRC_VENDOR_MIPS 0x40000000
+#define DRC_ZEROOPERANDS 0x80000000
+
+bool is_type_tag (uint16_t tag);
+bool is_pubtype_tag (uint16_t tag);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // liblldb_DWARFDefines_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
new file mode 100644
index 0000000..d2c137b
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,571 @@
+//===-- DWARFFormValue.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/Stream.h"
+
+#include "DWARFFormValue.h"
+#include "DWARFCompileUnit.h"
+
+class DWARFCompileUnit;
+
+using namespace lldb_private;
+
+DWARFFormValue::DWARFFormValue(dw_form_t form) :
+ m_form(form),
+ m_value()
+{
+}
+
+bool
+DWARFFormValue::ExtractValue(const DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu)
+{
+ bool indirect = false;
+ bool is_block = false;
+ m_value.data = NULL;
+ // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
+ do
+ {
+ indirect = false;
+ switch (m_form)
+ {
+ case DW_FORM_addr: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); break;
+ case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); is_block = true; break;
+ case DW_FORM_block4: m_value.value.uval = data.GetU32(offset_ptr); is_block = true; break;
+ case DW_FORM_data2: m_value.value.uval = data.GetU16(offset_ptr); break;
+ case DW_FORM_data4: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_data8: m_value.value.uval = data.GetU64(offset_ptr); break;
+ case DW_FORM_string: m_value.value.cstr = data.GetCStr(offset_ptr);
+ // Set the string value to also be the data for inlined cstr form values only
+ // so we can tell the differnence between DW_FORM_string and DW_FORM_strp form
+ // values;
+ m_value.data = (uint8_t*)m_value.value.cstr; break;
+ case DW_FORM_block: m_value.value.uval = data.GetULEB128(offset_ptr); is_block = true; break;
+ case DW_FORM_block1: m_value.value.uval = data.GetU8(offset_ptr); is_block = true; break;
+ case DW_FORM_data1: m_value.value.uval = data.GetU8(offset_ptr); break;
+ case DW_FORM_flag: m_value.value.uval = data.GetU8(offset_ptr); break;
+ case DW_FORM_sdata: m_value.value.sval = data.GetSLEB128(offset_ptr); break;
+ case DW_FORM_strp: m_value.value.uval = data.GetU32(offset_ptr); break;
+ // case DW_FORM_APPLE_db_str:
+ case DW_FORM_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break;
+ case DW_FORM_ref_addr: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); break;
+ case DW_FORM_ref1: m_value.value.uval = data.GetU8(offset_ptr); break;
+ case DW_FORM_ref2: m_value.value.uval = data.GetU16(offset_ptr); break;
+ case DW_FORM_ref4: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_ref8: m_value.value.uval = data.GetU64(offset_ptr); break;
+ case DW_FORM_ref_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break;
+ case DW_FORM_indirect:
+ m_form = data.GetULEB128(offset_ptr);
+ indirect = true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ } while (indirect);
+
+ if (is_block)
+ {
+ m_value.data = data.PeekData(*offset_ptr, m_value.value.uval);
+ if (m_value.data != NULL)
+ {
+ *offset_ptr += m_value.value.uval;
+ }
+ }
+
+ return true;
+}
+
+bool
+DWARFFormValue::SkipValue(const DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu) const
+{
+ return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, cu);
+}
+
+bool
+DWARFFormValue::SkipValue(dw_form_t form, const DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu)
+{
+ bool indirect = false;
+ do
+ {
+ indirect = false;
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_block : { dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block1 : { dw_uleb128_t size = debug_info_data.GetU8(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block2 : { dw_uleb128_t size = debug_info_data.GetU16(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block4 : { dw_uleb128_t size = debug_info_data.GetU32(offset_ptr); *offset_ptr += size; } return true;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string :
+ debug_info_data.GetCStr(offset_ptr);
+ return true;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ case DW_FORM_ref_addr :
+ *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
+ return true;
+
+ // 1 byte values
+ case DW_FORM_data1 :
+ case DW_FORM_flag :
+ case DW_FORM_ref1 :
+ *offset_ptr += 1;
+ return true;
+
+ // 2 byte values
+ case DW_FORM_data2 :
+ case DW_FORM_ref2 :
+ *offset_ptr += 2;
+ return true;
+
+ // 4 byte values
+ case DW_FORM_strp :
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ *offset_ptr += 4;
+ return true;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ *offset_ptr += 8;
+ return true;
+
+ // signed or unsigned LEB 128 values
+ // case DW_FORM_APPLE_db_str:
+ case DW_FORM_sdata :
+ case DW_FORM_udata :
+ case DW_FORM_ref_udata :
+ debug_info_data.Skip_LEB128(offset_ptr);
+ return true;
+
+ case DW_FORM_indirect :
+ indirect = true;
+ form = debug_info_data.GetULEB128(offset_ptr);
+ break;
+ default:
+ return false;
+ }
+ } while (indirect);
+ return true;
+}
+
+//bool
+//DWARFFormValue::PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs)
+//{
+// assert(offset != DW_INVALID_OFFSET);
+//// printf("PutUnsigned(%s, 0x%8.8x, 0x%16.16llx, %d)\n", DW_FORM_value_to_name(form), offset, value, fixup_cu_relative_refs);
+// // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
+// switch (form)
+// {
+// case DW_FORM_addr: offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu)); break;
+//
+// case DW_FORM_flag:
+// case DW_FORM_data1: offset = out_buff.Put8(offset, value); break;
+// case DW_FORM_data2: offset = out_buff.Put16(offset, value); break;
+// case DW_FORM_data4: offset = out_buff.Put32(offset, value); break;
+// case DW_FORM_data8: offset = out_buff.Put64(offset, value); break;
+//// case DW_FORM_udata: offset = out_buff.Put32_as_ULEB128(offset, value); break;
+//// case DW_FORM_sdata: offset = out_buff.Put32_as_SLEB128(offset, value); break;
+// case DW_FORM_strp: offset = out_buff.Put32(offset, value); break;
+//// case DW_FORM_APPLE_db_str:
+//// offset = out_buff.Put32_as_ULEB128(offset, value); break;
+//
+// case DW_FORM_ref1:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put8(offset, value);
+// break;
+// case DW_FORM_ref2:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put16(offset, value);
+// break;
+// case DW_FORM_ref4:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put32(offset, value);
+// break;
+// case DW_FORM_ref8:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put64(offset, value);
+// break;
+//// case DW_FORM_ref_udata:
+//// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+//// offset = out_buff.Put32_as_ULEB128(offset, value);
+//// break;
+// case DW_FORM_ref_addr:
+// // TODO: Add support for DWARF3 if we ever start emitting DWARF3. The DW_FORM_ref_addr
+// // is always the same size as an address prior to DWARF3, and with DWARF3 or later it
+// // is 4 hard coded to bytes.
+// offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu));
+// break;
+//
+// default:
+// return false;
+// }
+//
+// return true;
+//}
+
+//bool
+//DWARFFormValue::TransferValue(dw_form_t form, const DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff)
+//{
+// DWARFFormValue formValue(form);
+// if (formValue.ExtractValue(data, offset_ptr,cu))
+// return TransferValue(formValue, cu, out_buff);
+// return false;
+//}
+
+//bool
+//DWARFFormValue::TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff)
+//{
+// // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
+// dw_form_t form = formValue.Form();
+// switch (form)
+// {
+// case DW_FORM_addr:
+// case DW_FORM_ref_addr:
+// {
+// uint8_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu);
+// out_buff.AppendMax64(formValue.Unsigned(), addr_size);
+// }
+// break;
+//
+// case DW_FORM_block: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+// case DW_FORM_block1: out_buff.Append8(formValue.Unsigned()); break;
+// case DW_FORM_block2: out_buff.Append16(formValue.Unsigned()); break;
+// case DW_FORM_block4: out_buff.Append32(formValue.Unsigned()); break;
+//
+// case DW_FORM_flag:
+// case DW_FORM_data1: out_buff.Append8(formValue.Unsigned()); break;
+// case DW_FORM_data2: out_buff.Append16(formValue.Unsigned()); break;
+// case DW_FORM_data4: out_buff.Append32(formValue.Unsigned()); break;
+// case DW_FORM_data8: out_buff.Append64(formValue.Unsigned()); break;
+// case DW_FORM_udata: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+// case DW_FORM_sdata: out_buff.Append32_as_SLEB128(formValue.Signed()); break;
+//
+// case DW_FORM_string: out_buff.AppendCStr(formValue.m_value.value.cstr); break;
+// case DW_FORM_strp: out_buff.Append32(formValue.Unsigned()); break;
+//// case DW_FORM_APPLE_db_str:
+//// out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+//
+// case DW_FORM_ref1: out_buff.Append8(formValue.Unsigned()); break;
+// case DW_FORM_ref2: out_buff.Append16(formValue.Unsigned()); break;
+// case DW_FORM_ref4: out_buff.Append32(formValue.Unsigned()); break;
+// case DW_FORM_ref8: out_buff.Append64(formValue.Unsigned()); break;
+// case DW_FORM_ref_udata: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+//
+// case DW_FORM_indirect:
+// assert(!"DW_FORM_indirect found in DWARFFormValue::TransferValue() for an extracted form...");
+// break;
+//
+// default:
+// Log::Error("DWARFFormValue::TransferValue() Unrecognized form: 0x%4.4x", form);
+// return false;
+// break;
+// }
+//
+// const uint8_t* block_data = formValue.BlockData();
+// if (block_data)
+// out_buff.AppendData(block_data, formValue.Unsigned());
+// return true;
+//}
+
+void
+DWARFFormValue::Dump(Stream *s, const DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const
+{
+ uint64_t uvalue = Unsigned();
+ bool cu_relative_offset = false;
+
+ bool verbose = s->GetVerbose();
+
+ switch (m_form)
+ {
+ case DW_FORM_addr: s->Address(uvalue, sizeof (uint64_t)); break;
+ case DW_FORM_flag:
+ case DW_FORM_data1: s->PutHex8(uvalue); break;
+ case DW_FORM_data2: s->PutHex16(uvalue); break;
+ case DW_FORM_data4: s->PutHex32(uvalue); break;
+ case DW_FORM_data8: s->PutHex64(uvalue); break;
+ case DW_FORM_string: s->QuotedCString(AsCString(NULL)); break;
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (uvalue > 0)
+ {
+ switch (m_form)
+ {
+ case DW_FORM_block: s->Printf("<0x%llx> ", uvalue); break;
+ case DW_FORM_block1: s->Printf("<0x%2.2x> ", (uint8_t)uvalue); break;
+ case DW_FORM_block2: s->Printf("<0x%4.4x> ", (uint16_t)uvalue); break;
+ case DW_FORM_block4: s->Printf("<0x%8.8x> ", (uint32_t)uvalue); break;
+ default: break;
+ }
+
+ const uint8_t* data_ptr = m_value.data;
+ if (data_ptr)
+ {
+ const uint8_t* end_data_ptr = data_ptr + uvalue; // uvalue contains size of block
+ while (data_ptr < end_data_ptr)
+ {
+ s->Printf("%2.2x ", *data_ptr);
+ ++data_ptr;
+ }
+ }
+ else
+ s->PutCString("NULL");
+ }
+ break;
+
+ case DW_FORM_sdata: s->PutSLEB128(uvalue); break;
+ case DW_FORM_udata: s->PutULEB128(uvalue); break;
+ case DW_FORM_strp:
+ if (debug_str_data)
+ {
+ if (verbose)
+ s->Printf(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
+
+ const char* dbg_str = AsCString(debug_str_data);
+ if (dbg_str)
+ s->QuotedCString(dbg_str);
+ }
+ else
+ {
+ s->PutHex32(uvalue);
+ }
+ break;
+
+ case DW_FORM_ref_addr:
+ {
+ s->Address(uvalue, sizeof (uint64_t) * 2);
+ break;
+ }
+ case DW_FORM_ref1: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%2.2x", (uint8_t)uvalue); break;
+ case DW_FORM_ref2: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%4.4x", (uint16_t)uvalue); break;
+ case DW_FORM_ref4: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%4.4x", (uint32_t)uvalue); break;
+ case DW_FORM_ref8: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%8.8llx", uvalue); break;
+ case DW_FORM_ref_udata: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%llx", uvalue); break;
+
+ // All DW_FORM_indirect attributes should be resolved prior to calling this function
+ case DW_FORM_indirect: s->PutCString("DW_FORM_indirect"); break;
+ default:
+ s->Printf("DW_FORM(0x%4.4x)", m_form);
+ break;
+ }
+
+ if (cu_relative_offset)
+ {
+ if (verbose)
+ s->PutCString(" => ");
+
+ s->Printf("{0x%8.8x}", (uvalue + (cu ? cu->GetOffset() : 0)));
+ }
+}
+
+const char*
+DWARFFormValue::AsCString(const DataExtractor* debug_str_data_ptr) const
+{
+ if (IsInlinedCStr())
+ return m_value.value.cstr;
+ else if (debug_str_data_ptr)
+ return debug_str_data_ptr->PeekCStr(m_value.value.uval);
+ return NULL;
+}
+
+uint64_t
+DWARFFormValue::Reference(const DWARFCompileUnit* cu) const
+{
+ uint64_t die_offset = m_value.value.uval;
+ switch (m_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ die_offset += (cu ? cu->GetOffset() : 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return die_offset;
+}
+
+//----------------------------------------------------------------------
+// Resolve any compile unit specific references so that we don't need
+// the compile unit at a later time in order to work with the form
+// value.
+//----------------------------------------------------------------------
+bool
+DWARFFormValue::ResolveCompileUnitReferences(const DWARFCompileUnit* cu)
+{
+ switch (m_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ m_value.value.uval += cu->GetOffset();
+ m_form = DW_FORM_ref_addr;
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+const uint8_t*
+DWARFFormValue::BlockData() const
+{
+ if (!IsInlinedCStr())
+ return m_value.data;
+ return NULL;
+}
+
+
+bool
+DWARFFormValue::IsBlockForm(const dw_form_t form)
+{
+ switch (form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ return true;
+ }
+ return false;
+}
+
+bool
+DWARFFormValue::IsDataForm(const dw_form_t form)
+{
+ switch (form)
+ {
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ return true;
+ }
+ return false;
+}
+
+int
+DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DataExtractor* debug_str_data_ptr)
+{
+ dw_form_t a_form = a_value.Form();
+ dw_form_t b_form = b_value.Form();
+ if (a_form < b_form)
+ return -1;
+ if (a_form > b_form)
+ return 1;
+ switch (a_form)
+ {
+ case DW_FORM_addr:
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ case DW_FORM_ref_addr:
+ {
+ uint64_t a = a_value.Unsigned();
+ uint64_t b = b_value.Unsigned();
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_sdata:
+ {
+ int64_t a = a_value.Signed();
+ int64_t b = b_value.Signed();
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ {
+ const char *a_string = a_value.AsCString(debug_str_data_ptr);
+ const char *b_string = b_value.AsCString(debug_str_data_ptr);
+ if (a_string == b_string)
+ return 0;
+ else if (a_string && b_string)
+ return strcmp(a_string, b_string);
+ else if (a_string == NULL)
+ return -1; // A string is NULL, and B is valid
+ else
+ return 1; // A string valid, and B is NULL
+ }
+
+
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ {
+ uint64_t a_len = a_value.Unsigned();
+ uint64_t b_len = b_value.Unsigned();
+ if (a_len < b_len)
+ return -1;
+ if (a_len > b_len)
+ return 1;
+ // The block lengths are the same
+ return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned());
+ }
+ break;
+
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ {
+ uint64_t a = a_value.Reference(a_cu);
+ uint64_t b = b_value.Reference(b_cu);
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_indirect:
+ assert(!"This shouldn't happen after the form has been extracted...");
+ break;
+
+ default:
+ assert(!"Unhandled DW_FORM");
+ break;
+ }
+ return -1;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
new file mode 100644
index 0000000..3db6366
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
@@ -0,0 +1,81 @@
+//===-- DWARFFormValue.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_DWARFFormValue_h_
+ #define SymbolFileDWARF_DWARFFormValue_h_
+
+#include "SymbolFileDWARF.h"
+#include <stddef.h> // for NULL
+
+class DWARFFormValue
+{
+public:
+ typedef struct ValueTypeTag
+ {
+ ValueTypeTag() :
+ data(NULL),
+ value()
+ {
+ value.uval = 0;
+ }
+
+ union
+ {
+ uint64_t uval;
+ int64_t sval;
+ const char* cstr;
+ } value;
+ const uint8_t* data;
+ } ValueType;
+
+ enum
+ {
+ eValueTypeInvalid = 0,
+ eValueTypeUnsigned,
+ eValueTypeSigned,
+ eValueTypeCStr,
+ eValueTypeBlock
+ };
+
+ DWARFFormValue(dw_form_t form = 0);
+ dw_form_t Form() const { return m_form; }
+ void SetForm(dw_form_t form) { m_form = form; }
+ const ValueType& Value() const { return m_value; }
+ void Dump(lldb_private::Stream *s, const lldb_private::DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const;
+ bool ExtractValue(const lldb_private::DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu);
+ bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (uint8_t*)m_value.value.cstr; }
+ const uint8_t* BlockData() const;
+ uint64_t Reference(const DWARFCompileUnit* cu) const;
+ bool ResolveCompileUnitReferences(const DWARFCompileUnit* cu);
+ uint64_t Unsigned() const { return m_value.value.uval; }
+ void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; }
+ int64_t Signed() const { return m_value.value.sval; }
+ void SetSigned(int64_t sval) { m_value.value.sval = sval; }
+ const char* AsCString(const lldb_private::DataExtractor* debug_str_data_ptr) const;
+ bool SkipValue(const lldb_private::DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu) const;
+ static bool SkipValue(const dw_form_t form, const lldb_private::DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu);
+// static bool TransferValue(dw_form_t form, const lldb_private::DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff);
+// static bool TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff);
+// static bool PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs);
+ static bool IsBlockForm(const dw_form_t form);
+ static bool IsDataForm(const dw_form_t form);
+
+ static int Compare (const DWARFFormValue& a, const DWARFFormValue& b, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const lldb_private::DataExtractor* debug_str_data_ptr);
+protected:
+ dw_form_t m_form; // Form for this value
+ ValueType m_value; // Contains all data for the form
+};
+
+
+#endif // SymbolFileDWARF_DWARFFormValue_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp
new file mode 100644
index 0000000..9229c2a
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp
@@ -0,0 +1,172 @@
+//===-- DWARFLocationDescription.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationDescription.h"
+#include "DWARFDefines.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Stream.h"
+
+
+using namespace lldb_private;
+
+static int print_dwarf_exp_op (Stream *s, const DataExtractor& data, uint32_t* offset_ptr, int address_size, int dwarf_ref_size);
+
+int
+print_dwarf_expression (Stream *s,
+ const DataExtractor& data,
+ int address_size,
+ int dwarf_ref_size,
+ bool location_expression)
+{
+ int op_count = 0;
+ uint32_t offset = 0;
+ while (data.ValidOffset(offset))
+ {
+ if (location_expression && op_count > 0)
+ {
+ // err (baton, "Dwarf location expressions may only have one operand!");
+ return 1;
+ }
+ if (op_count > 0)
+ {
+ s->PutCString(", ");
+ }
+ if (print_dwarf_exp_op (s, data, &offset, address_size, dwarf_ref_size) == 1)
+ return 1;
+ op_count++;
+ }
+
+ return 0;
+}
+
+static int
+print_dwarf_exp_op (Stream *s,
+ const DataExtractor& data,
+ uint32_t* offset_ptr,
+ int address_size,
+ int dwarf_ref_size)
+{
+ uint8_t opcode = data.GetU8(offset_ptr);
+ DRC_class opcode_class;
+ uint64_t uint;
+ int64_t sint;
+
+ int size;
+
+ opcode_class = DW_OP_value_to_class (opcode) & (~DRC_DWARFv3);
+
+ s->Printf("%s ", DW_OP_value_to_englishy_name (opcode));
+
+ /* Does this take zero parameters? If so we can shortcut this function. */
+ if (opcode_class == DRC_ZEROOPERANDS)
+ return 0;
+
+ if (opcode_class == DRC_TWOOPERANDS && opcode == DW_OP_bregx)
+ {
+ uint = data.GetULEB128(offset_ptr);
+ sint = data.GetSLEB128(offset_ptr);
+ s->Printf("%llu %lli", uint, sint);
+ return 0;
+ }
+ if (opcode_class != DRC_ONEOPERAND)
+ {
+ s->Printf("UNKNOWN OP %u", opcode);
+ return 1;
+ }
+
+ switch (opcode)
+ {
+ case DW_OP_addr: size = address_size; break;
+ case DW_OP_const1u: size = 1; break;
+ case DW_OP_const1s: size = -1; break;
+ case DW_OP_const2u: size = 2; break;
+ case DW_OP_const2s: size = -2; break;
+ case DW_OP_const4u: size = 4; break;
+ case DW_OP_const4s: size = -4; break;
+ case DW_OP_const8u: size = 8; break;
+ case DW_OP_const8s: size = -8; break;
+ case DW_OP_constu: size = 128; break;
+ case DW_OP_consts: size = -128; break;
+ case DW_OP_fbreg: size = -128; 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:
+ size = -128; break;
+ case DW_OP_pick:
+ size = 1; break;
+ case DW_OP_deref_size:
+ size = 1; break;
+ case DW_OP_xderef_size:
+ size = 1; break;
+ case DW_OP_plus_uconst:
+ size = 128; break;
+ case DW_OP_skip:
+ size = -2; break;
+ case DW_OP_bra:
+ size = -2; break;
+ case DW_OP_call2:
+ size = 2; break;
+ case DW_OP_call4:
+ size = 4; break;
+ case DW_OP_call_ref:
+ size = dwarf_ref_size; break;
+ case DW_OP_piece:
+ size = 128; break;
+ case DW_OP_regx:
+ size = 128; break;
+ default:
+ s->Printf("UNKNOWN ONE-OPERAND OPCODE, #%u", opcode);
+ return 1;
+ }
+
+ switch (size)
+ {
+ case -1: sint = (int8_t) data.GetU8(offset_ptr); s->Printf("%+lli", sint); break;
+ case -2: sint = (int16_t) data.GetU16(offset_ptr); s->Printf("%+lli", sint); break;
+ case -4: sint = (int32_t) data.GetU32(offset_ptr); s->Printf("%+lli", sint); break;
+ case -8: sint = (int64_t) data.GetU64(offset_ptr); s->Printf("%+lli", sint); break;
+ case -128: sint = data.GetSLEB128(offset_ptr); s->Printf("%+lli", sint); break;
+ case 1: uint = data.GetU8(offset_ptr); s->Printf("0x%2.2llx", uint); break;
+ case 2: uint = data.GetU16(offset_ptr); s->Printf("0x%4.4llx", uint); break;
+ case 4: uint = data.GetU32(offset_ptr); s->Printf("0x%8.8llx", uint); break;
+ case 8: uint = data.GetU64(offset_ptr); s->Printf("0x%16.16llx", uint); break;
+ case 128: uint = data.GetULEB128(offset_ptr); s->Printf("0x%llx", uint); break;
+ }
+
+ return 0;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h
new file mode 100644
index 0000000..413a95c
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h
@@ -0,0 +1,24 @@
+//===-- DWARFLocationDescription.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_DWARFLocationDescription_h_
+#define SymbolFileDWARF_DWARFLocationDescription_h_
+
+#include "SymbolFileDWARF.h"
+
+int
+print_dwarf_expression (lldb_private::Stream *s,
+ const lldb_private::DataExtractor& data,
+ int address_size,
+ int dwarf_ref_size,
+ bool location_expression);
+
+
+
+#endif // SymbolFileDWARF_DWARFLocationDescription_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
new file mode 100644
index 0000000..6a8359d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
@@ -0,0 +1,89 @@
+//===-- DWARFLocationList.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationList.h"
+
+#include "lldb/Core/Stream.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFLocationDescription.h"
+
+using namespace lldb_private;
+
+dw_offset_t
+DWARFLocationList::Dump(Stream *s, const DWARFCompileUnit* cu, const DataExtractor& debug_loc_data, dw_offset_t offset)
+{
+ uint64_t start_addr, end_addr;
+ uint32_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu);
+ s->SetAddressByteSize(DWARFCompileUnit::GetAddressByteSize(cu));
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ while (debug_loc_data.ValidOffset(offset))
+ {
+ start_addr = debug_loc_data.GetMaxU64(&offset,addr_size);
+ end_addr = debug_loc_data.GetMaxU64(&offset,addr_size);
+
+ if (start_addr == 0 && end_addr == 0)
+ break;
+
+ s->PutCString("\n ");
+ s->Indent();
+ s->AddressRange(start_addr + base_addr, end_addr + base_addr, NULL, ": ");
+ uint32_t loc_length = debug_loc_data.GetU16(&offset);
+
+ DataExtractor locationData(debug_loc_data, offset, loc_length);
+ // if ( dump_flags & DWARFDebugInfo::eDumpFlag_Verbose ) *ostrm_ptr << " ( ";
+ print_dwarf_expression (s, locationData, addr_size, 4, false);
+ offset += loc_length;
+ }
+
+ return offset;
+}
+
+bool
+DWARFLocationList::Extract(const DataExtractor& debug_loc_data, dw_offset_t* offset_ptr, DataExtractor& location_list_data)
+{
+ // Initialize with no data just in case we don't find anything
+ location_list_data.Clear();
+
+ size_t loc_list_length = Size(debug_loc_data, *offset_ptr);
+ if (loc_list_length > 0)
+ {
+ location_list_data.SetData(debug_loc_data, *offset_ptr, loc_list_length);
+ *offset_ptr += loc_list_length;
+ return true;
+ }
+
+ return false;
+}
+
+size_t
+DWARFLocationList::Size(const DataExtractor& debug_loc_data, dw_offset_t offset)
+{
+ const dw_offset_t debug_loc_offset = offset;
+
+ while (debug_loc_data.ValidOffset(offset))
+ {
+ dw_addr_t start_addr = debug_loc_data.GetAddress(&offset);
+ dw_addr_t end_addr = debug_loc_data.GetAddress(&offset);
+
+ if (start_addr == 0 && end_addr == 0)
+ break;
+
+ uint16_t loc_length = debug_loc_data.GetU16(&offset);
+ offset += loc_length;
+ }
+
+ if (offset > debug_loc_offset)
+ return offset - debug_loc_offset;
+ return 0;
+}
+
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h
new file mode 100644
index 0000000..3efd5c4
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h
@@ -0,0 +1,34 @@
+//===-- DWARFLocationList.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_DWARFLocationList_h_
+#define SymbolFileDWARF_DWARFLocationList_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFLocationList
+{
+public:
+ static dw_offset_t
+ Dump (lldb_private::Stream *s,
+ const DWARFCompileUnit* cu,
+ const lldb_private::DataExtractor& debug_loc_data,
+ dw_offset_t offset);
+
+ static bool
+ Extract (const lldb_private::DataExtractor& debug_loc_data,
+ dw_offset_t* offset_ptr,
+ lldb_private::DataExtractor& location_list_data);
+
+ static size_t
+ Size (const lldb_private::DataExtractor& debug_loc_data,
+ dw_offset_t offset);
+
+};
+#endif // SymbolFileDWARF_DWARFLocationList_h_
diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
new file mode 100644
index 0000000..571271b
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
@@ -0,0 +1,207 @@
+//===-- LogChannelDWARF.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LogChannelDWARF.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// when the one and only logging channel is abled, then this will be non NULL.
+static LogChannelDWARF* g_log_channel = NULL;
+
+LogChannelDWARF::LogChannelDWARF () :
+ LogChannel ()
+{
+}
+
+LogChannelDWARF::~LogChannelDWARF ()
+{
+}
+
+
+void
+LogChannelDWARF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ LogChannelDWARF::CreateInstance);
+}
+
+void
+LogChannelDWARF::Terminate()
+{
+ PluginManager::UnregisterPlugin (LogChannelDWARF::CreateInstance);
+}
+
+LogChannel*
+LogChannelDWARF::CreateInstance ()
+{
+ return new LogChannelDWARF ();
+}
+
+const char *
+LogChannelDWARF::GetPluginNameStatic()
+{
+ static std::string g_plugin_name;
+ if (g_plugin_name.empty())
+ {
+ g_plugin_name = SymbolFileDWARF::GetPluginNameStatic();
+ g_plugin_name += LogChannel::GetPluginSuffix ();
+ }
+ return g_plugin_name.c_str();
+}
+
+
+const char *
+LogChannelDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF log channel for debugging plug-in issues.";
+}
+
+const char *
+LogChannelDWARF::GetPluginName()
+{
+ return GetPluginDescriptionStatic();
+}
+
+const char *
+LogChannelDWARF::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+LogChannelDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+
+void
+LogChannelDWARF::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+
+Error
+LogChannelDWARF::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorStringWithFormat("No commands are supported.\n");
+ return error;
+}
+
+
+Log *
+LogChannelDWARF::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+void
+LogChannelDWARF::Disable ()
+{
+ g_log_channel = NULL;
+ m_log_sp.reset();
+}
+
+bool
+LogChannelDWARF::Enable
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Stream *feedback_strm, // Feedback stream for argument errors etc
+ const Args &categories // The categories to enable within this logging stream, if empty, enable default set
+)
+{
+ Disable ();
+
+ m_log_sp.reset(new Log (log_stream_sp));
+ g_log_channel = this;
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ const size_t argc = categories.GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *arg = categories.GetArgumentAtIndex(i);
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= DWARF_LOG_ALL;
+ else if (::strcasecmp (arg, "info") == 0 ) flag_bits |= DWARF_LOG_DEBUG_INFO;
+ else if (::strcasecmp (arg, "line") == 0 ) flag_bits |= DWARF_LOG_DEBUG_LINE;
+ else if (::strcasecmp (arg, "pubnames") == 0 ) flag_bits |= DWARF_LOG_DEBUG_PUBNAMES;
+ else if (::strcasecmp (arg, "pubtypes") == 0 ) flag_bits |= DWARF_LOG_DEBUG_PUBTYPES;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= DWARF_LOG_DEFAULT;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = DWARF_LOG_DEFAULT;
+ m_log_sp->GetMask().SetAllFlagBits(flag_bits);
+ m_log_sp->GetOptions().SetAllFlagBits(log_options);
+ return m_log_sp.get() != NULL;
+}
+
+void
+LogChannelDWARF::ListCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " info - log the parsing if .debug_info\n"
+ " line - log the parsing if .debug_line\n"
+ " pubnames - log the parsing if .debug_pubnames\n"
+ " pubtypes - log the parsing if .debug_pubtypes\n\n",
+ SymbolFileDWARF::GetPluginNameStatic());
+}
+
+Log *
+LogChannelDWARF::GetLog ()
+{
+ if (g_log_channel)
+ return g_log_channel->m_log_sp.get();
+ else
+ return NULL;
+}
+
+Log *
+LogChannelDWARF::GetLogIfAll (uint32_t mask)
+{
+ Log *log = GetLog();
+ if (log)
+ if (log->GetMask().IsSet(mask))
+ return log;
+ return NULL;
+}
+
+
+void
+LogChannelDWARF::LogIf (uint32_t mask, const char *format, ...)
+{
+ if (g_log_channel)
+ {
+ LogSP log_sp(g_log_channel->m_log_sp);
+ va_list args;
+ va_start (args, format);
+ log_sp->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
new file mode 100644
index 0000000..943d1da
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
@@ -0,0 +1,91 @@
+//===-- LogChannelDWARF.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_LogChannelDWARF_h_
+#define liblldb_LogChannelDWARF_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define DWARF_LOG_VERBOSE (1u << 0)
+#define DWARF_LOG_DEBUG_INFO (1u << 1)
+#define DWARF_LOG_DEBUG_LINE (1u << 2)
+#define DWARF_LOG_DEBUG_PUBNAMES (1u << 3)
+#define DWARF_LOG_DEBUG_PUBTYPES (1u << 4)
+#define DWARF_LOG_ALL (UINT32_MAX)
+#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO)
+
+class LogChannelDWARF : public lldb_private::LogChannel
+{
+public:
+ LogChannelDWARF ();
+
+ virtual
+ ~LogChannelDWARF ();
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::LogChannel *
+ CreateInstance ();
+
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+ virtual void
+ Disable ();
+
+ virtual bool
+ Enable (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ lldb_private::Stream *feedback_strm, // Feedback stream for argument errors etc
+ const lldb_private::Args &categories); // The categories to enable within this logging stream, if empty, enable default set
+
+ virtual void
+ ListCategories (lldb_private::Stream *strm);
+
+ static lldb_private::Log *
+ GetLog ();
+
+ static lldb_private::Log *
+ GetLogIfAll (uint32_t mask);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_LogChannelDWARF_h_
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
new file mode 100644
index 0000000..ffee695
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -0,0 +1,3615 @@
+//===-- SymbolFileDWARF.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+// Other libraries and framework includes
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Specifiers.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFDebugLine.h"
+#include "DWARFDebugPubnames.h"
+#include "DWARFDebugRanges.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFLocationList.h"
+#include "LogChannelDWARF.h"
+
+#include <map>
+
+#define DIE_IS_BEING_PARSED ((void*)1)
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static const ConstString&
+GetSectionNameDebugInfo()
+{
+ static const ConstString g_sect_name("__debug_info");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugAbbrev()
+{
+ static const ConstString g_sect_name ("__debug_abbrev");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugAranges()
+{
+ static const ConstString g_sect_name ("__debug_aranges");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugFrame()
+{
+ static const ConstString g_sect_name ("__debug_frame");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugLine()
+{
+ static const ConstString g_sect_name ("__debug_line");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugLoc()
+{
+ static const ConstString g_sect_name ("__debug_loc");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugMacInfo()
+{
+ static const ConstString g_sect_name ("__debug_macinfo");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugPubNames()
+{
+ static const ConstString g_sect_name ("__debug_pubnames");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugPubTypes()
+{
+ static const ConstString g_sect_name ("__debug_pubtypes");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugRanges()
+{
+ static const ConstString g_sect_name ("__debug_ranges");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugStr()
+{
+ static const ConstString g_sect_name ("__debug_str");
+ return g_sect_name;
+}
+
+static uint32_t
+DwarfToClangAccessibility (uint32_t dwarf_accessibility)
+{
+ switch (dwarf_accessibility)
+ {
+ case DW_ACCESS_public:
+ return clang::AS_public;
+ case DW_ACCESS_private:
+ return clang::AS_private;
+ case DW_ACCESS_protected:
+ return clang::AS_protected;
+ default:
+ return clang::AS_none;
+ }
+}
+
+void
+SymbolFileDWARF::Initialize()
+{
+ LogChannelDWARF::Initialize();
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+ LogChannelDWARF::Initialize();
+}
+
+
+const char *
+SymbolFileDWARF::GetPluginNameStatic()
+{
+ return "symbol-file.dwarf2";
+}
+
+const char *
+SymbolFileDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF and DWARF3 debug symbol file reader.";
+}
+
+
+SymbolFile*
+SymbolFileDWARF::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileDWARF(obj_file);
+}
+
+//----------------------------------------------------------------------
+// Gets the first parent that is a lexical block, function or inlined
+// subroutine, or compile unit.
+//----------------------------------------------------------------------
+static const DWARFDebugInfoEntry *
+GetParentSymbolContextDIE(const DWARFDebugInfoEntry *child_die)
+{
+ const DWARFDebugInfoEntry *die;
+ for (die = child_die->GetParent(); die != NULL; die = die->GetParent())
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ return die;
+ }
+ }
+ return NULL;
+}
+
+
+SymbolFileDWARF::SymbolFileDWARF(ObjectFile* ofile) :
+ SymbolFile(ofile),
+ m_flags(),
+ m_data_debug_abbrev(),
+ m_data_debug_aranges(),
+ m_data_debug_frame(),
+ m_data_debug_info(),
+ m_data_debug_line(),
+ m_data_debug_loc(),
+ m_data_debug_macinfo(),
+ m_data_debug_pubnames(),
+ m_data_debug_pubtypes(),
+ m_data_debug_ranges(),
+ m_data_debug_str(),
+ m_abbr(),
+ m_aranges(),
+ m_info(),
+ m_line(),
+ m_name_to_function_die(),
+ m_name_to_inlined_die(),
+ m_name_to_global_die(),
+ m_name_to_type_die(),
+ m_indexed(false),
+// m_pubnames(),
+// m_pubtypes(),
+// m_pubbasetypes(),
+ m_ranges()//,
+// m_type_fixups(),
+// m_indirect_fixups()
+{
+}
+
+SymbolFileDWARF::~SymbolFileDWARF()
+{
+}
+
+bool
+SymbolFileDWARF::SupportedVersion(uint16_t version)
+{
+ return version == 2 || version == 3;
+}
+
+uint32_t
+SymbolFileDWARF::GetAbilities ()
+{
+ uint32_t abilities = 0;
+ if (m_obj_file != NULL)
+ {
+ const Section* section = NULL;
+ const SectionList *section_list = m_obj_file->GetSectionList();
+ if (section_list == NULL)
+ return 0;
+
+ uint64_t debug_abbrev_file_size = 0;
+ uint64_t debug_aranges_file_size = 0;
+ uint64_t debug_frame_file_size = 0;
+ uint64_t debug_info_file_size = 0;
+ uint64_t debug_line_file_size = 0;
+ uint64_t debug_loc_file_size = 0;
+ uint64_t debug_macinfo_file_size = 0;
+ uint64_t debug_pubnames_file_size = 0;
+ uint64_t debug_pubtypes_file_size = 0;
+ uint64_t debug_ranges_file_size = 0;
+ uint64_t debug_str_file_size = 0;
+
+ static ConstString g_dwarf_section_name ("__DWARF");
+
+ section = section_list->FindSectionByName(g_dwarf_section_name).get();
+
+ if (section)
+ section->MemoryMapSectionDataFromObjectFile(m_obj_file, m_dwarf_data);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugInfo()).get();
+ if (section != NULL)
+ {
+ debug_info_file_size = section->GetByteSize();
+
+ section = section_list->FindSectionByName (GetSectionNameDebugAbbrev()).get();
+ if (section)
+ debug_abbrev_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugAbbrevData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugAranges()).get();
+ if (section)
+ debug_aranges_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugArangesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugFrame()).get();
+ if (section)
+ debug_frame_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugFrameData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugLine()).get();
+ if (section)
+ debug_line_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugLineData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugLoc()).get();
+ if (section)
+ debug_loc_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugLocData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugMacInfo()).get();
+ if (section)
+ debug_macinfo_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugMacInfoData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugPubNames()).get();
+ if (section)
+ debug_pubnames_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugPubNamesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugPubTypes()).get();
+ if (section)
+ debug_pubtypes_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugPubTypesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugRanges()).get();
+ if (section)
+ debug_ranges_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugRangesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugStr()).get();
+ if (section)
+ debug_str_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugStrData);
+ }
+
+ if (debug_abbrev_file_size > 0 && debug_info_file_size > 0)
+ abilities |= CompileUnits | Functions | Blocks | GlobalVariables | LocalVariables | VariableTypes;
+
+ if (debug_line_file_size > 0)
+ abilities |= LineTables;
+
+ if (debug_aranges_file_size > 0)
+ abilities |= AddressAcceleratorTable;
+
+ if (debug_pubnames_file_size > 0)
+ abilities |= FunctionAcceleratorTable;
+
+ if (debug_pubtypes_file_size > 0)
+ abilities |= TypeAcceleratorTable;
+
+ if (debug_macinfo_file_size > 0)
+ abilities |= MacroInformation;
+
+ if (debug_frame_file_size > 0)
+ abilities |= CallFrameInformation;
+ }
+ return abilities;
+}
+
+const DataExtractor&
+SymbolFileDWARF::GetCachedSectionData (uint32_t got_flag, const ConstString §ion_name, DataExtractor &data)
+{
+ if (m_flags.IsClear (got_flag))
+ {
+ m_flags.Set (got_flag);
+ const SectionList *section_list = m_obj_file->GetSectionList();
+ if (section_list)
+ {
+ Section *section = section_list->FindSectionByName (section_name).get();
+ if (section )
+ {
+ // See if we memory mapped the DWARF segment?
+ if (m_dwarf_data.GetByteSize())
+ {
+ data.SetData(m_dwarf_data, section->GetOffset (), section->GetByteSize());
+ }
+ else
+ {
+ if (section->ReadSectionDataFromObjectFile(m_obj_file, data) == 0)
+ data.Clear();
+ }
+ }
+ }
+ }
+ return data;
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_abbrev_data()
+{
+ return GetCachedSectionData (flagsGotDebugAbbrevData, GetSectionNameDebugAbbrev(), m_data_debug_abbrev);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_aranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugArangesData, GetSectionNameDebugAranges(), m_data_debug_aranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_frame_data()
+{
+ return GetCachedSectionData (flagsGotDebugFrameData, GetSectionNameDebugFrame(), m_data_debug_frame);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_info_data()
+{
+ return GetCachedSectionData (flagsGotDebugInfoData, GetSectionNameDebugInfo(), m_data_debug_info);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_line_data()
+{
+ return GetCachedSectionData (flagsGotDebugLineData, GetSectionNameDebugLine(), m_data_debug_line);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_loc_data()
+{
+ return GetCachedSectionData (flagsGotDebugLocData, GetSectionNameDebugLoc(), m_data_debug_loc);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_macinfo_data()
+{
+ return GetCachedSectionData (flagsGotDebugMacInfoData, GetSectionNameDebugMacInfo(), m_data_debug_macinfo);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_pubnames_data()
+{
+ return GetCachedSectionData (flagsGotDebugPubNamesData, GetSectionNameDebugPubNames(), m_data_debug_pubnames);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_pubtypes_data()
+{
+ return GetCachedSectionData (flagsGotDebugPubTypesData, GetSectionNameDebugPubTypes(), m_data_debug_pubtypes);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_ranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugRangesData, GetSectionNameDebugRanges(), m_data_debug_ranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_str_data()
+{
+ return GetCachedSectionData (flagsGotDebugStrData, GetSectionNameDebugStr(), m_data_debug_str);
+}
+
+
+DWARFDebugAbbrev*
+SymbolFileDWARF::DebugAbbrev()
+{
+ if (m_abbr.get() == NULL)
+ {
+ const DataExtractor &debug_abbrev_data = get_debug_abbrev_data();
+ if (debug_abbrev_data.GetByteSize() > 0)
+ {
+ m_abbr.reset(new DWARFDebugAbbrev());
+ if (m_abbr.get())
+ m_abbr->Parse(debug_abbrev_data);
+ }
+ }
+ return m_abbr.get();
+}
+
+const DWARFDebugAbbrev*
+SymbolFileDWARF::DebugAbbrev() const
+{
+ return m_abbr.get();
+}
+
+DWARFDebugAranges*
+SymbolFileDWARF::DebugAranges()
+{
+ if (m_aranges.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ m_aranges.reset(new DWARFDebugAranges());
+ if (m_aranges.get())
+ {
+ const DataExtractor &debug_aranges_data = get_debug_aranges_data();
+ if (debug_aranges_data.GetByteSize() > 0)
+ m_aranges->Extract(debug_aranges_data);
+ else
+ m_aranges->Generate(this);
+ }
+ }
+ return m_aranges.get();
+}
+
+const DWARFDebugAranges*
+SymbolFileDWARF::DebugAranges() const
+{
+ return m_aranges.get();
+}
+
+
+DWARFDebugInfo*
+SymbolFileDWARF::DebugInfo()
+{
+ if (m_info.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ if (get_debug_info_data().GetByteSize() > 0)
+ {
+ m_info.reset(new DWARFDebugInfo());
+ if (m_info.get())
+ {
+ m_info->SetDwarfData(this);
+ }
+ }
+ }
+ return m_info.get();
+}
+
+const DWARFDebugInfo*
+SymbolFileDWARF::DebugInfo() const
+{
+ return m_info.get();
+}
+
+//DWARFDebugLine*
+//SymbolFileDWARF::DebugLine()
+//{
+// if (m_line.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__);
+// const DataExtractor &debug_line_data = debug_line();
+// if (debug_line_data.GetByteSize() > 0)
+// {
+// m_line.reset(new DWARFDebugLine());
+// if (m_line.get())
+// m_line->Parse(debug_line_data);
+// }
+// }
+// return m_line.get();
+//}
+//
+//const DWARFDebugLine*
+//SymbolFileDWARF::DebugLine() const
+//{
+// return m_line.get();
+//}
+
+
+DWARFCompileUnit*
+SymbolFileDWARF::GetDWARFCompileUnitForUID(lldb::user_id_t cu_uid)
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ return info->GetCompileUnit(cu_uid).get();
+ return NULL;
+}
+
+//DWARFCompileUnit*
+//SymbolFileDWARF::GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu)
+//{
+// DWARFCompileUnit* cu = NULL;
+// DWARFDebugInfo* info = DebugInfo();
+// if (info)
+// {
+// uint32_t cu_idx = 0;
+// if (prev_cu != NULL)
+// {
+// // Find the index of the previus DWARF compile unit if one was provided
+// while ((cu = info->GetCompileUnitAtIndex(cu_idx)) != NULL)
+// {
+// ++cu_idx;
+// if (cu == prev_cu)
+// break;
+// }
+// }
+//
+// // Now find the next unparsed DWARF compile unit. We do this by checking the
+// // user data in the DWARFCompileUnit class that starts as NULL, and eventually
+// // holds a pointer to the CompileUnit that was created for it after it has
+// // been parsed.
+// while ((cu = info->GetCompileUnitAtIndex(cu_idx)) != NULL)
+// {
+// if (cu->GetUserData() == NULL)
+// break;
+// }
+// }
+// return cu;
+//}
+
+DWARFDebugRanges*
+SymbolFileDWARF::DebugRanges()
+{
+ if (m_ranges.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ if (get_debug_ranges_data().GetByteSize() > 0)
+ {
+ m_ranges.reset(new DWARFDebugRanges());
+ if (m_ranges.get())
+ m_ranges->Extract(this);
+ }
+ }
+ return m_ranges.get();
+}
+
+const DWARFDebugRanges*
+SymbolFileDWARF::DebugRanges() const
+{
+ return m_ranges.get();
+}
+//
+//DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubnames()
+//{
+// if (m_pubnames.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+// const DataExtractor &debug_pubnames_data = get_debug_pubnames_data();
+// if (debug_pubnames_data.GetByteSize() > 0)
+// {
+// // Pass false to indicate this is a pubnames section
+// m_pubnames.reset(new DWARFDebugPubnames());
+// if (m_pubnames.get())
+// {
+// // "m_pubnames->GeneratePubnames" is costly, but needed for global variables
+// m_pubnames->GeneratePubnames(this);
+//
+//#if 0
+// StreamFile s(stdout);
+// s.Printf (".debug_pubnames for %s/%s:\n",
+// m_obj_file->GetModule()->GetFileSpec().GetDirectory().AsCString(),
+// m_obj_file->GetModule()->GetFileSpec().GetFilename().AsCString());
+// m_pubnames->Dump (&s);
+//#endif
+// // "m_pubnames->Extract" is quicker, but the pubnames don't always contain what we need.
+// //m_pubnames->Extract(debug_pubnames_data);
+// }
+// }
+// }
+// return m_pubnames.get();
+//}
+//
+//const DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubnames() const
+//{
+// return m_pubnames.get();
+//}
+
+//DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubBaseTypes()
+//{
+// if (m_pubbasetypes.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+// // Pass false to indicate this is a pubnames section
+// m_pubbasetypes.reset(new DWARFDebugPubnames());
+// if (m_pubbasetypes.get())
+// m_pubbasetypes->GeneratePubBaseTypes(this);
+// }
+// return m_pubbasetypes.get();
+//}
+//
+//const DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubBaseTypes() const
+//{
+// return m_pubbasetypes.get();
+//}
+//
+//const DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubtypes() const
+//{
+// return m_pubtypes.get();
+//}
+//
+//DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubtypes()
+//{
+// if (m_pubtypes.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+// const DataExtractor &debug_pubtypes_data = get_debug_pubtypes_data();
+// if (debug_pubtypes_data.GetByteSize() > 0)
+// {
+// // Pass false to indicate this is a pubnames section
+// m_pubtypes.reset(new DWARFDebugPubnames());
+// if (m_pubtypes.get())
+// m_pubtypes->Extract(debug_pubtypes_data);
+// }
+// }
+// return m_pubtypes.get();
+//}
+//
+
+bool
+SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit* cu, CompUnitSP& compile_unit_sp)
+{
+ if (cu != NULL)
+ {
+ const DWARFDebugInfoEntry * cu_die = cu->GetCompileUnitDIEOnly ();
+ if (cu_die)
+ {
+ const char * cu_die_name = cu_die->GetName(this, cu);
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, cu, DW_AT_comp_dir, NULL);
+ Language::Type language = (Language::Type)cu_die->GetAttributeValueAsUnsigned(this, cu, DW_AT_language, 0);
+ if (cu_die_name)
+ {
+ if (cu_die_name[0] == '/' || cu_comp_dir == NULL && cu_comp_dir[0])
+ {
+ compile_unit_sp.reset(new CompileUnit(m_obj_file->GetModule(), cu, cu_die_name, cu->GetOffset(), language));
+ }
+ else
+ {
+ std::string fullpath(cu_comp_dir);
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ fullpath += cu_die_name;
+
+ compile_unit_sp.reset(new CompileUnit(m_obj_file->GetModule(), cu, fullpath.c_str(), cu->GetOffset(), language));
+ }
+
+ if (compile_unit_sp.get())
+ {
+ cu->SetUserData(compile_unit_sp.get());
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+#if defined LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST
+
+void
+SymbolFileDWARF::ShrinkDSYM(CompileUnit *dc_cu, DWARFCompileUnit *dw_cu, const FileSpec& cu_fspec, const FileSpec& base_types_fspec, FSToDIES& fs_to_dies, const DWARFDebugInfoEntry *die)
+{
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ // Put all base types into the base type compile unit
+ fs_to_dies[base_types_fspec].Insert(die);
+ break;
+
+ default:
+ {
+ uint32_t decl_file = die->GetAttributeValueAsUnsigned(this, dw_cu, DW_AT_decl_file, 0);
+ if (decl_file)
+ {
+ fs_to_dies[dc_cu->GetSupportFiles().GetFileSpecAtIndex(decl_file)].Insert(die);
+ }
+ else
+ {
+ // add this to the current compile unit
+ fs_to_dies[cu_fspec].Insert(die);
+ }
+ }
+ break;
+ }
+
+ die = die->GetSibling();
+ }
+}
+
+
+
+#endif
+
+uint32_t
+SymbolFileDWARF::GetNumCompileUnits()
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+#if defined LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST
+ uint32_t cu_idx;
+ FSToDIES fs_to_dies;
+
+ FileSpec base_type_fspec("DW_TAG_base_type");
+ const uint32_t num_comp_units = info->GetNumCompileUnits();
+
+ for (cu_idx=0; cu_idx < num_comp_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (cu != NULL)
+ {
+ const DWARFDebugInfoEntry *cu_die = cu->DIE();
+ if (cu_die)
+ {
+ CompUnitSP dc_cu_sp;
+ ParseCompileUnit(cu, dc_cu_sp);
+ if (dc_cu_sp.get())
+ {
+ FileSpec cu_fspec(*dc_cu_sp.get());
+
+ ShrinkDSYM(dc_cu_sp.get(), cu, cu_fspec, base_type_fspec, fs_to_dies, cu->DIE()->GetFirstChild());
+ }
+ }
+ }
+ }
+
+ Stream strm(stdout);
+ FSToDIES::const_iterator pos, end = fs_to_dies.end();
+ for (pos = fs_to_dies.begin(); pos != end; ++pos)
+ {
+ strm << "\n\nMinimal Compile Unit: " << pos->first << ":\n";
+ const DWARFDIECollection& dies = pos->second;
+ dies.Dump(strm, NULL);
+ }
+ return num_comp_units;
+#else
+ return info->GetNumCompileUnits();
+#endif
+ }
+ return 0;
+}
+
+CompUnitSP
+SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx)
+{
+ CompUnitSP comp_unit;
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ DWARFCompileUnit* cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (cu != NULL)
+ {
+ // Our symbol vendor shouldn't be asking us to add a compile unit that
+ // has already been added to it, which this DWARF plug-in knows as it
+ // stores the lldb compile unit (CompileUnit) pointer in each
+ // DWARFCompileUnit object when it gets added.
+ assert(cu->GetUserData() == NULL);
+ ParseCompileUnit(cu, comp_unit);
+ }
+ }
+ return comp_unit;
+}
+
+static void
+AddRangesToBlock
+(
+ BlockList& blocks,
+ lldb::user_id_t blockID,
+ DWARFDebugRanges::RangeList& ranges,
+ addr_t block_base_addr
+)
+{
+ ranges.SubtractOffset (block_base_addr);
+ size_t range_idx = 0;
+ const DWARFDebugRanges::Range *debug_range;
+ for (range_idx = 0; (debug_range = ranges.RangeAtIndex(range_idx)) != NULL; range_idx++)
+ {
+ blocks.AddRange(blockID, debug_range->begin_offset, debug_range->end_offset);
+ }
+}
+
+
+Function *
+SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die)
+{
+ DWARFDebugRanges::RangeList func_ranges;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ int decl_file = 0;
+ int decl_line = 0;
+ int decl_column = 0;
+ int call_file = 0;
+ int call_line = 0;
+ int call_column = 0;
+ DWARFExpression frame_base;
+
+ // Parse the function prototype as a type that can then be added to concrete function instance
+ ParseTypes (sc, dwarf_cu, die, false, false);
+ //FixupTypes();
+
+ if (die->GetDIENamesAndRanges(this, dwarf_cu, name, mangled, func_ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column, &frame_base))
+ {
+ // Union of all ranges in the function DIE (if the function is discontiguous)
+ AddressRange func_range;
+ lldb::addr_t lowest_func_addr = func_ranges.LowestAddress(0);
+ lldb::addr_t highest_func_addr = func_ranges.HighestAddress(0);
+ if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr)
+ {
+ func_range.GetBaseAddress().ResolveAddressUsingFileSections (lowest_func_addr, m_obj_file->GetSectionList());
+ if (func_range.GetBaseAddress().IsValid())
+ func_range.SetByteSize(highest_func_addr - lowest_func_addr);
+ }
+
+ if (func_range.GetBaseAddress().IsValid())
+ {
+ Mangled func_name;
+ if (mangled)
+ func_name.SetValue(mangled, true);
+ else if (name)
+ func_name.SetValue(name, false);
+
+ FunctionSP func_sp;
+ std::auto_ptr<Declaration> decl_ap;
+ if (decl_file != 0 || decl_line != 0 || decl_column != 0)
+ decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, decl_column));
+
+ Type *func_type = NULL;
+
+ if (die->GetUserData() != DIE_IS_BEING_PARSED)
+ func_type = (Type*)die->GetUserData();
+
+ assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED);
+
+ func_range.GetBaseAddress().ResolveLinkedAddress();
+
+ func_sp.reset(new Function (sc.comp_unit,
+ die->GetOffset(), // UserID is the DIE offset
+ die->GetOffset(),
+ func_name,
+ func_type,
+ func_range)); // first address range
+
+ if (func_sp.get() != NULL)
+ {
+ func_sp->GetFrameBaseExpression() = frame_base;
+ sc.comp_unit->AddFunction(func_sp);
+ return func_sp.get();
+ }
+ }
+ }
+ return NULL;
+}
+
+size_t
+SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ size_t functions_added = 0;
+ const DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ if (dwarf_cu)
+ {
+ DWARFDIECollection function_dies;
+ const size_t num_funtions = dwarf_cu->AppendDIEsWithTag (DW_TAG_subprogram, function_dies);
+ size_t func_idx;
+ for (func_idx = 0; func_idx < num_funtions; ++func_idx)
+ {
+ const DWARFDebugInfoEntry *die = function_dies.GetDIEPtrAtIndex(func_idx);
+ if (sc.comp_unit->FindFunctionByUID (die->GetOffset()).get() == NULL)
+ {
+ if (ParseCompileUnitFunction(sc, dwarf_cu, die))
+ ++functions_added;
+ }
+ }
+ //FixupTypes();
+ }
+ return functions_added;
+}
+
+bool
+SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files)
+{
+ assert (sc.comp_unit);
+ DWARFCompileUnit* cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ assert (cu);
+ const DWARFDebugInfoEntry * cu_die = cu->GetCompileUnitDIEOnly();
+
+ if (cu_die)
+ {
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, cu, DW_AT_comp_dir, NULL);
+ dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, cu, DW_AT_stmt_list, DW_INVALID_OFFSET);
+
+ // All file indexes in DWARF are one based and a file of index zero is
+ // supposed to be the compile unit itself.
+ support_files.Append (*sc.comp_unit);
+
+ return DWARFDebugLine::ParseSupportFiles(get_debug_line_data(), cu_comp_dir, stmt_list, support_files);
+ }
+ return false;
+}
+
+struct ParseDWARFLineTableCallbackInfo
+{
+ LineTable* line_table;
+ const SectionList *section_list;
+ lldb::addr_t prev_sect_file_base_addr;
+ lldb::addr_t curr_sect_file_base_addr;
+ bool is_oso_for_debug_map;
+ bool prev_in_final_executable;
+ DWARFDebugLine::Row prev_row;
+ SectionSP prev_section_sp;
+ SectionSP curr_section_sp;
+};
+
+//----------------------------------------------------------------------
+// ParseStatementTableCallback
+//----------------------------------------------------------------------
+static void
+ParseDWARFLineTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ LineTable* line_table = ((ParseDWARFLineTableCallbackInfo*)userData)->line_table;
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // Just started parsing the line table
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table, nothing to do for the cleanup
+ }
+ else
+ {
+ ParseDWARFLineTableCallbackInfo* info = (ParseDWARFLineTableCallbackInfo*)userData;
+ // We have a new row, lets append it
+
+ if (info->curr_section_sp.get() == NULL || info->curr_section_sp->ContainsFileAddress(state.address) == false)
+ {
+ info->prev_section_sp = info->curr_section_sp;
+ info->prev_sect_file_base_addr = info->curr_sect_file_base_addr;
+ // If this is an end sequence entry, then we subtract one from the
+ // address to make sure we get an address that is not the end of
+ // a section.
+ if (state.end_sequence && state.address != 0)
+ info->curr_section_sp = info->section_list->FindSectionContainingFileAddress (state.address - 1);
+ else
+ info->curr_section_sp = info->section_list->FindSectionContainingFileAddress (state.address);
+
+ if (info->curr_section_sp.get())
+ info->curr_sect_file_base_addr = info->curr_section_sp->GetFileAddress ();
+ else
+ info->curr_sect_file_base_addr = 0;
+ }
+ if (info->curr_section_sp.get())
+ {
+ lldb::addr_t curr_line_section_offset = state.address - info->curr_sect_file_base_addr;
+ // Check for the fancy section magic to determine if we
+
+ if (info->is_oso_for_debug_map)
+ {
+ // When this is a debug map object file that contains DWARF
+ // (referenced from an N_OSO debug map nlist entry) we will have
+ // a file address in the file range for our section from the
+ // original .o file, and a load address in the executable that
+ // contains the debug map.
+ //
+ // If the sections for the file range and load range are
+ // different, we have a remapped section for the function and
+ // this address is resolved. If they are the same, then the
+ // function for this address didn't make it into the final
+ // executable.
+ bool curr_in_final_executable = info->curr_section_sp->GetLinkedSection () != NULL;
+
+ // If we are doing DWARF with debug map, then we need to carefully
+ // add each line table entry as there may be gaps as functions
+ // get moved around or removed.
+ if (!info->prev_row.end_sequence && info->prev_section_sp.get())
+ {
+ if (info->prev_in_final_executable)
+ {
+ bool terminate_previous_entry = false;
+ if (!curr_in_final_executable)
+ {
+ // Check for the case where the previous line entry
+ // in a function made it into the final executable,
+ // yet the current line entry falls in a function
+ // that didn't. The line table used to be contiguous
+ // through this address range but now it isn't. We
+ // need to terminate the previous line entry so
+ // that we can reconstruct the line range correctly
+ // for it and to keep the line table correct.
+ terminate_previous_entry = true;
+ }
+ else if (info->curr_section_sp.get() != info->prev_section_sp.get())
+ {
+ // Check for cases where the line entries used to be
+ // contiguous address ranges, but now they aren't.
+ // This can happen when order files specify the
+ // ordering of the functions.
+ lldb::addr_t prev_line_section_offset = info->prev_row.address - info->prev_sect_file_base_addr;
+ Section *curr_sect = info->curr_section_sp.get();
+ Section *prev_sect = info->prev_section_sp.get();
+ assert (curr_sect->GetLinkedSection());
+ assert (prev_sect->GetLinkedSection());
+ lldb::addr_t object_file_addr_delta = state.address - info->prev_row.address;
+ lldb::addr_t curr_linked_file_addr = curr_sect->GetLinkedFileAddress() + curr_line_section_offset;
+ lldb::addr_t prev_linked_file_addr = prev_sect->GetLinkedFileAddress() + prev_line_section_offset;
+ lldb::addr_t linked_file_addr_delta = curr_linked_file_addr - prev_linked_file_addr;
+ if (object_file_addr_delta != linked_file_addr_delta)
+ terminate_previous_entry = true;
+ }
+
+ if (terminate_previous_entry)
+ {
+ line_table->InsertLineEntry (info->prev_section_sp,
+ state.address - info->prev_sect_file_base_addr,
+ info->prev_row.line,
+ info->prev_row.column,
+ info->prev_row.file,
+ false, // is_stmt
+ false, // basic_block
+ false, // state.prologue_end
+ false, // state.epilogue_begin
+ true); // end_sequence);
+ }
+ }
+ }
+
+ if (curr_in_final_executable)
+ {
+ line_table->InsertLineEntry (info->curr_section_sp,
+ curr_line_section_offset,
+ state.line,
+ state.column,
+ state.file,
+ state.is_stmt,
+ state.basic_block,
+ state.prologue_end,
+ state.epilogue_begin,
+ state.end_sequence);
+ info->prev_section_sp = info->curr_section_sp;
+ }
+ else
+ {
+ // If the current address didn't make it into the final
+ // executable, the current section will be the __text
+ // segment in the .o file, so we need to clear this so
+ // we can catch the next function that did make it into
+ // the final executable.
+ info->prev_section_sp.reset();
+ info->curr_section_sp.reset();
+ }
+
+ info->prev_in_final_executable = curr_in_final_executable;
+ }
+ else
+ {
+ // We are not in an object file that contains DWARF for an
+ // N_OSO, this is just a normal DWARF file. The DWARF spec
+ // guarantees that the addresses will be in increasing order
+ // so, since we store line tables in file address order, we
+ // can always just append the line entry without needing to
+ // search for the correct insertion point (we don't need to
+ // use LineEntry::InsertLineEntry()).
+ line_table->AppendLineEntry (info->curr_section_sp,
+ curr_line_section_offset,
+ state.line,
+ state.column,
+ state.file,
+ state.is_stmt,
+ state.basic_block,
+ state.prologue_end,
+ state.epilogue_begin,
+ state.end_sequence);
+ }
+ }
+
+ info->prev_row = state;
+ }
+}
+
+bool
+SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ if (sc.comp_unit->GetLineTable() != NULL)
+ return true;
+
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly();
+ const dw_offset_t cu_line_offset = dwarf_cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET);
+ if (cu_line_offset != DW_INVALID_OFFSET)
+ {
+ std::auto_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit));
+ if (line_table_ap.get())
+ {
+ ParseDWARFLineTableCallbackInfo info = { line_table_ap.get(), m_obj_file->GetSectionList(), 0, 0, m_flags.IsSet (flagsDWARFIsOSOForDebugMap), false};
+ uint32_t offset = cu_line_offset;
+ DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info);
+ sc.comp_unit->SetLineTable(line_table_ap.release());
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+SymbolFileDWARF::ParseFunctionBlocks
+(
+ const SymbolContext& sc,
+ lldb::user_id_t parentBlockID,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ addr_t subprogram_low_pc,
+ bool parse_siblings,
+ bool parse_children
+)
+{
+ size_t blocks_added = 0;
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ {
+ DWARFDebugRanges::RangeList ranges;
+ const char *name = NULL;
+ const char *mangled_name = NULL;
+ BlockList& blocks = sc.function->GetBlocks(false);
+
+ lldb::user_id_t blockID = blocks.AddChild(parentBlockID, die->GetOffset());
+ int decl_file = 0;
+ int decl_line = 0;
+ int decl_column = 0;
+ int call_file = 0;
+ int call_line = 0;
+ int call_column = 0;
+ if (die->GetDIENamesAndRanges(this, dwarf_cu, name, mangled_name, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column))
+ {
+ if (tag == DW_TAG_subprogram)
+ {
+ assert (subprogram_low_pc == LLDB_INVALID_ADDRESS);
+ subprogram_low_pc = ranges.LowestAddress(0);
+ }
+
+ AddRangesToBlock (blocks, blockID, ranges, subprogram_low_pc);
+
+ if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL))
+ {
+ std::auto_ptr<Declaration> decl_ap;
+ if (decl_file != 0 || decl_line != 0 || decl_column != 0)
+ decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, decl_column));
+
+ std::auto_ptr<Declaration> call_ap;
+ if (call_file != 0 || call_line != 0 || call_column != 0)
+ call_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file), call_line, call_column));
+
+ blocks.SetInlinedFunctionInfo(blockID, name, mangled_name, decl_ap.get(), call_ap.get());
+ }
+
+ ++blocks_added;
+
+ if (parse_children && die->HasChildren())
+ {
+ blocks_added += ParseFunctionBlocks(sc, blockID, dwarf_cu, die->GetFirstChild(), subprogram_low_pc, true, true);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+ return blocks_added;
+}
+
+size_t
+SymbolFileDWARF::ParseChildMembers
+(
+ const SymbolContext& sc,
+ TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ int& default_accessibility,
+ bool &is_a_class
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+
+ size_t count = 0;
+ const DWARFDebugInfoEntry *die;
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_member:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ DWARFExpression location;
+ const char *name = NULL;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ uint32_t accessibility = clang::AS_none;
+ off_t member_offset = 0;
+ size_t byte_size = 0;
+ size_t bit_offset = 0;
+ size_t bit_size = 0;
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_bit_offset: bit_offset = form_value.Unsigned(); break;
+ case DW_AT_bit_size: bit_size = form_value.Unsigned(); break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_data_member_location:
+ if (form_value.BlockData())
+ {
+ Value initialValue(0);
+ Value memberOffset(0);
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ uint32_t block_length = form_value.Unsigned();
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ if (DWARFExpression::Evaluate(NULL, NULL, debug_info_data, NULL, NULL, block_offset, block_length, eRegisterKindDWARF, &initialValue, memberOffset, NULL))
+ {
+ member_offset = memberOffset.ResolveValue(NULL, NULL).UInt();
+ }
+ }
+ break;
+
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility (form_value.Unsigned()); break;
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_mutable:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ Type *member_type = ResolveTypeUID(encoding_uid);
+ assert(member_type);
+ if (accessibility == clang::AS_none)
+ accessibility = default_accessibility;
+ member_accessibilities.push_back(accessibility);
+
+ type_list->GetClangASTContext().AddFieldToRecordType (type_sp->GetOpaqueClangQualType(), name, member_type->GetOpaqueClangQualType(), accessibility, bit_size);
+ }
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ {
+ is_a_class = true;
+ if (default_accessibility == clang::AS_none)
+ default_accessibility = clang::AS_private;
+ // TODO: implement DW_TAG_subprogram type parsing
+// UserDefTypeChildInfo method_info(die->GetOffset());
+//
+// FunctionSP func_sp (sc.comp_unit->FindFunctionByUID (die->GetOffset()));
+// if (func_sp.get() == NULL)
+// ParseCompileUnitFunction(sc, dwarf_cu, die);
+//
+// method_info.SetEncodingTypeUID(die->GetOffset());
+// struct_udt->AddMethod(method_info);
+ }
+ break;
+
+ case DW_TAG_inheritance:
+ {
+ is_a_class = true;
+ if (default_accessibility == clang::AS_none)
+ default_accessibility = clang::AS_private;
+ // TODO: implement DW_TAG_inheritance type parsing
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ DWARFExpression location;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ uint32_t accessibility = default_accessibility;
+ bool is_virtual = false;
+ bool is_base_of_class = true;
+ off_t member_offset = 0;
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_data_member_location:
+ if (form_value.BlockData())
+ {
+ Value initialValue(0);
+ Value memberOffset(0);
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ uint32_t block_length = form_value.Unsigned();
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ if (DWARFExpression::Evaluate(NULL, NULL, debug_info_data, NULL, NULL, block_offset, block_length, eRegisterKindDWARF, &initialValue, memberOffset, NULL))
+ {
+ member_offset = memberOffset.ResolveValue(NULL, NULL).UInt();
+ }
+ }
+ break;
+
+ case DW_AT_accessibility:
+ accessibility = DwarfToClangAccessibility(form_value.Unsigned());
+ break;
+
+ case DW_AT_virtuality: is_virtual = form_value.Unsigned() != 0; break;
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ Type *base_class_dctype = ResolveTypeUID(encoding_uid);
+ assert(base_class_dctype);
+ base_classes.push_back (type_list->GetClangASTContext().CreateBaseClassSpecifier (base_class_dctype->GetOpaqueClangQualType(), accessibility, is_virtual, is_base_of_class));
+ assert(base_classes.back());
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return count;
+}
+
+
+clang::DeclContext*
+SymbolFileDWARF::GetClangDeclContextForTypeUID (lldb::user_id_t type_uid)
+{
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ if (die)
+ return GetClangDeclContextForDIE (cu_sp.get(), die);
+ }
+ return NULL;
+}
+
+Type*
+SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, NULL);
+ if (type_die != NULL)
+ {
+ void *type = type_die->GetUserData();
+ if (type == NULL)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ if (die != NULL)
+ {
+ TypeSP owning_type_sp;
+ TypeSP type_sp(GetTypeForDIE(cu_sp.get(), die, owning_type_sp, 0, 0));
+ }
+ type = type_die->GetUserData();
+ }
+ if (type != DIE_IS_BEING_PARSED)
+ return (Type *)type;
+ }
+ }
+ return NULL;
+}
+
+CompileUnit*
+SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit* cu, uint32_t cu_idx)
+{
+ // Check if the symbol vendor already knows about this compile unit?
+ if (cu->GetUserData() == NULL)
+ {
+ // The symbol vendor doesn't know about this compile unit, we
+ // need to parse and add it to the symbol vendor object.
+ CompUnitSP dc_cu;
+ ParseCompileUnit(cu, dc_cu);
+ if (dc_cu.get())
+ {
+ // Figure out the compile unit index if we weren't given one
+ if (cu_idx == UINT_MAX)
+ DebugInfo()->GetCompileUnit(cu->GetOffset(), &cu_idx);
+
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(dc_cu, cu_idx);
+ }
+ }
+ return (CompileUnit*)cu->GetUserData();
+}
+
+bool
+SymbolFileDWARF::GetFunction (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* func_die, SymbolContext& sc)
+{
+ sc.Clear();
+ // Check if the symbol vendor already knows about this compile unit?
+ sc.module_sp = m_obj_file->GetModule()->GetSP();
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX);
+
+ sc.function = sc.comp_unit->FindFunctionByUID (func_die->GetOffset()).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, cu, func_die);
+
+ return sc.function != NULL;
+}
+
+uint32_t
+SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::ResolveSymbolContext (so_addr = { section = %p, offset = 0x%llx }, resolve_scope = 0x%8.8x)",
+ so_addr.GetSection(),
+ so_addr.GetOffset(),
+ resolve_scope);
+ uint32_t resolved = 0;
+ if (resolve_scope & ( eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextBlock |
+ eSymbolContextLineEntry))
+ {
+ lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
+
+ DWARFDebugAranges* debug_aranges = DebugAranges();
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_aranges)
+ {
+ dw_offset_t cu_offset = debug_aranges->FindAddress(file_vm_addr);
+ if (cu_offset != DW_INVALID_OFFSET)
+ {
+ uint32_t cu_idx;
+ DWARFCompileUnit* cu = debug_info->GetCompileUnit(cu_offset, &cu_idx).get();
+ if (cu)
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, cu_idx);
+ assert(sc.comp_unit != NULL);
+ resolved |= eSymbolContextCompUnit;
+
+ if (resolve_scope & eSymbolContextLineEntry)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table == NULL)
+ {
+ if (ParseCompileUnitLineTable(sc))
+ line_table = sc.comp_unit->GetLineTable();
+ }
+ if (line_table != NULL)
+ {
+ if (so_addr.IsLinkedAddress())
+ {
+ Address linked_addr (so_addr);
+ linked_addr.ResolveLinkedAddress();
+ if (line_table->FindLineEntryByAddress (linked_addr, sc.line_entry))
+ {
+ resolved |= eSymbolContextLineEntry;
+ }
+ }
+ else if (line_table->FindLineEntryByAddress (so_addr, sc.line_entry))
+ {
+ resolved |= eSymbolContextLineEntry;
+ }
+ }
+ }
+
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock))
+ {
+ DWARFDebugInfoEntry *function_die = NULL;
+ DWARFDebugInfoEntry *block_die = NULL;
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ cu->LookupAddress(file_vm_addr, &function_die, &block_die);
+ }
+ else
+ {
+ cu->LookupAddress(file_vm_addr, &function_die, NULL);
+ }
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (function_die->GetOffset()).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, cu, function_die);
+ }
+
+ if (sc.function != NULL)
+ {
+ resolved |= eSymbolContextFunction;
+
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ BlockList& blocks = sc.function->GetBlocks(true);
+
+ if (block_die != NULL)
+ sc.block = blocks.GetBlockByID(block_die->GetOffset());
+ else
+ sc.block = blocks.GetBlockByID(function_die->GetOffset());
+ if (sc.block)
+ resolved |= eSymbolContextBlock;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return resolved;
+}
+
+
+
+uint32_t
+SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ const uint32_t prev_size = sc_list.GetSize();
+ if (resolve_scope & eSymbolContextCompUnit)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx;
+ DWARFCompileUnit* cu = NULL;
+
+ for (cu_idx = 0; (cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; ++cu_idx)
+ {
+ CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(cu, cu_idx);
+ bool file_spec_matches_cu_file_spec = dc_cu != NULL && FileSpec::Compare(file_spec, *dc_cu, false) == 0;
+ if (check_inlines || file_spec_matches_cu_file_spec)
+ {
+ SymbolContext sc (m_obj_file->GetModule());
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, cu_idx);
+ assert(sc.comp_unit != NULL);
+
+ uint32_t file_idx = UINT32_MAX;
+
+ // If we are looking for inline functions only and we don't
+ // find it in the support files, we are done.
+ if (check_inlines)
+ {
+ file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec);
+ if (file_idx == UINT32_MAX)
+ continue;
+ }
+
+ if (line != 0)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table != NULL && line != 0)
+ {
+ // We will have already looked up the file index if
+ // we are searching for inline entries.
+ if (!check_inlines)
+ file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec);
+
+ if (file_idx != UINT32_MAX)
+ {
+ uint32_t found_line;
+ uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_idx, line, false, &sc.line_entry);
+ found_line = sc.line_entry.line;
+
+ while (line_idx != UINT_MAX)
+ {
+ sc.function = NULL;
+ sc.block = NULL;
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock))
+ {
+ const lldb::addr_t file_vm_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress();
+ if (file_vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ DWARFDebugInfoEntry *function_die = NULL;
+ DWARFDebugInfoEntry *block_die = NULL;
+ cu->LookupAddress(file_vm_addr, &function_die, resolve_scope & eSymbolContextBlock ? &block_die : NULL);
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (function_die->GetOffset()).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, cu, function_die);
+ }
+
+ if (sc.function != NULL)
+ {
+ BlockList& blocks = sc.function->GetBlocks(true);
+
+ if (block_die != NULL)
+ sc.block = blocks.GetBlockByID(block_die->GetOffset());
+ else
+ sc.block = blocks.GetBlockByID(function_die->GetOffset());
+ }
+ }
+ }
+
+ sc_list.Append(sc);
+ line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_idx, found_line, true, &sc.line_entry);
+ }
+ }
+ }
+ else if (file_spec_matches_cu_file_spec && !check_inlines)
+ {
+ // only append the context if we aren't looking for inline call sites
+ // by file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+ }
+ else if (file_spec_matches_cu_file_spec && !check_inlines)
+ {
+ // only append the context if we aren't looking for inline call sites
+ // by file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+
+ if (!check_inlines)
+ break;
+ }
+ }
+ }
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+void
+SymbolFileDWARF::Index ()
+{
+ if (m_indexed)
+ return;
+ m_indexed = true;
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::Index (%s)",
+ GetObjectFile()->GetFileSpec().GetFilename().AsCString());
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
+
+ cu->Index (m_name_to_function_die,
+ m_name_to_inlined_die,
+ m_name_to_global_die,
+ m_name_to_type_die);
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ cu->ClearDIEs (true);
+ }
+
+ m_name_to_function_die.Sort();
+ m_name_to_inlined_die.Sort();
+ m_name_to_global_die.Sort();
+ m_name_to_type_die.Sort();
+ }
+}
+
+uint32_t
+SymbolFileDWARF::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
+{
+ std::vector<dw_offset_t> die_offsets;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ const UniqueCStringMap<dw_offset_t>::Entry *entry;
+
+ for (entry = m_name_to_global_die.FindFirstValueForName (name.AsCString());
+ entry != NULL;
+ entry = m_name_to_global_die.FindNextValueForName (name.AsCString(), entry))
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (entry->value, &cu_sp);
+ DWARFCompileUnit* cu = cu_sp.get();
+ if (die)
+ {
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule()->GetSP();
+ assert (sc.module_sp);
+
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX);
+ assert(sc.comp_unit != NULL);
+
+ ParseVariables(sc, cu_sp.get(), die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ break;
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ std::vector<dw_offset_t> die_offsets;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ const size_t num_entries = m_name_to_global_die.GetSize();
+ for (size_t i=0; i<num_entries; i++)
+ {
+ if (!regex.Execute(m_name_to_global_die.GetCStringAtIndex (i)))
+ continue;
+
+ const dw_offset_t die_offset = *m_name_to_global_die.GetValueAtIndex (i);
+
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (die_offset, &cu_sp);
+ DWARFCompileUnit* cu = cu_sp.get();
+ if (die)
+ {
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule()->GetSP();
+ assert (sc.module_sp);
+
+
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX);
+ assert(sc.comp_unit != NULL);
+
+ ParseVariables(sc, cu_sp.get(), die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ break;
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+uint32_t
+SymbolFileDWARF::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (name = '%s')",
+ name.AsCString());
+
+ std::vector<dw_offset_t> die_offsets;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ sc_list.Clear();
+
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+ uint32_t original_size = sc_list.GetSize();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ const UniqueCStringMap<dw_offset_t>::Entry *entry;
+
+ SymbolContext sc;
+ for (entry = m_name_to_function_die.FindFirstValueForName (name.AsCString());
+ entry != NULL;
+ entry = m_name_to_function_die.FindNextValueForName (name.AsCString(), entry))
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (entry->value, &cu_sp);
+ if (die)
+ {
+ if (GetFunction (cu_sp.get(), die, sc))
+ {
+ // We found the function, so we should find the line table
+ // and line table entry as well
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table == NULL)
+ {
+ if (ParseCompileUnitLineTable(sc))
+ line_table = sc.comp_unit->GetLineTable();
+ }
+ if (line_table != NULL)
+ line_table->FindLineEntryByAddress (sc.function->GetAddressRange().GetBaseAddress(), sc.line_entry);
+
+ sc_list.Append(sc);
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return sc_list.GetSize() - original_size;
+}
+
+
+uint32_t
+SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ std::vector<dw_offset_t> die_offsets;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ sc_list.Clear();
+
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+ uint32_t original_size = sc_list.GetSize();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ const size_t num_entries = m_name_to_function_die.GetSize();
+ SymbolContext sc;
+ for (size_t i=0; i<num_entries; i++)
+ {
+ if (!regex.Execute(m_name_to_function_die.GetCStringAtIndex (i)))
+ continue;
+
+ const dw_offset_t die_offset = *m_name_to_function_die.GetValueAtIndex (i);
+
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (die_offset, &cu_sp);
+ if (die)
+ {
+ if (GetFunction (cu_sp.get(), die, sc))
+ {
+ // We found the function, so we should find the line table
+ // and line table entry as well
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table == NULL)
+ {
+ if (ParseCompileUnitLineTable(sc))
+ line_table = sc.comp_unit->GetLineTable();
+ }
+ if (line_table != NULL)
+ line_table->FindLineEntryByAddress (sc.function->GetAddressRange().GetBaseAddress(), sc.line_entry);
+
+
+ sc_list.Append(sc);
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return sc_list.GetSize() - original_size;
+}
+
+#if 0
+uint32_t
+SymbolFileDWARF::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+{
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ types.Clear();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ DWARFDebugPubnames* pubtypes = DebugPubtypes();
+ if (pubtypes)
+ {
+ std::vector<dw_offset_t> die_offsets;
+ if (!pubtypes->Find(name.AsCString(), false, die_offsets))
+ {
+ DWARFDebugPubnames* pub_base_types = DebugPubBaseTypes();
+ if (pub_base_types && !pub_base_types->Find(name.AsCString(), false, die_offsets))
+ return 0;
+ }
+ return FindTypes(die_offsets, max_matches, encoding, udt_uid, types);
+ }
+ return 0;
+}
+
+
+uint32_t
+SymbolFileDWARF::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+{
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ types.Clear();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ DWARFDebugPubnames* pubtypes = DebugPubtypes();
+ if (pubtypes)
+ {
+ std::vector<dw_offset_t> die_offsets;
+ if (!pubtypes->Find(regex, die_offsets))
+ {
+ DWARFDebugPubnames* pub_base_types = DebugPubBaseTypes();
+ if (pub_base_types && !pub_base_types->Find(regex, die_offsets))
+ return 0;
+ }
+
+ return FindTypes(die_offsets, max_matches, encoding, udt_uid, types);
+ }
+
+ return 0;
+}
+
+
+
+uint32_t
+SymbolFileDWARF::FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+{
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+ uint32_t original_size = types.Size();
+
+ const uint32_t num_die_offsets = die_offsets.size();
+ // Parse all of the types we found from the pubtypes matches
+ uint32_t i;
+ uint32_t num_matches = 0;
+ for (i = 0; i < num_die_offsets; ++i)
+ {
+ dw_offset_t die_offset = die_offsets[i];
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp);
+
+ assert(die != NULL);
+
+ bool get_type_for_die = true;
+ if (encoding)
+ {
+ // Check if this type has already been uniqued and registers with the module?
+ Type* type = (Type*)die->GetUserData();
+ if (type != NULL && type != DIE_IS_BEING_PARSED)
+ {
+ get_type_for_die = type->GetEncoding() == encoding;
+ }
+ else
+ {
+ dw_tag_t tag = die->Tag();
+ switch (encoding)
+ {
+ case Type::address:
+ case Type::boolean:
+ case Type::complex_float:
+ case Type::float_type:
+ case Type::signed_int:
+ case Type::signed_char:
+ case Type::unsigned_int:
+ case Type::unsigned_char:
+ case Type::imaginary_float:
+ case Type::packed_decimal:
+ case Type::numeric_string:
+ case Type::edited_string:
+ case Type::signed_fixed:
+ case Type::unsigned_fixed:
+ case Type::decimal_float:
+ if (tag != DW_TAG_base_type)
+ get_type_for_die = false;
+ else
+ {
+ if (die->GetAttributeValueAsUnsigned(this, cu_sp.get(), DW_AT_encoding, Type::invalid) != encoding)
+ get_type_for_die = false;
+ }
+ break;
+
+ case Type::indirect_const: get_type_for_die = tag == DW_TAG_const_type; break;
+ case Type::indirect_restrict: get_type_for_die = tag == DW_TAG_restrict_type; break;
+ case Type::indirect_volatile: get_type_for_die = tag == DW_TAG_volatile_type; break;
+ case Type::indirect_typedef: get_type_for_die = tag == DW_TAG_typedef; break;
+ case Type::indirect_pointer: get_type_for_die = tag == DW_TAG_pointer_type; break;
+ case Type::indirect_reference: get_type_for_die = tag == DW_TAG_reference_type; break;
+
+ case Type::user_defined_type:
+ switch (tag)
+ {
+ case DW_TAG_array_type:
+ get_type_for_die = UserDefTypeArray::OwnsUserDefTypeUID(udt_uid);
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ get_type_for_die = UserDefTypeStruct::OwnsUserDefTypeUID(udt_uid);
+ break;
+
+ case DW_TAG_enumeration_type:
+ get_type_for_die = UserDefTypeEnum::OwnsUserDefTypeUID(udt_uid);
+ break;
+
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ get_type_for_die = UserDefTypeFunction::OwnsUserDefTypeUID(udt_uid);
+ break;
+ }
+ }
+ }
+ }
+
+ if (get_type_for_die)
+ {
+ TypeSP owning_type_sp;
+ TypeSP type_sp(GetTypeForDIE(cu_sp.get(), die, owning_type_sp, NULL, 0, 0));
+
+ if (type_sp.get())
+ {
+ // See if we are filtering results based on encoding?
+ bool add_type = (encoding == Type::invalid);
+ if (!add_type)
+ {
+ // We are filtering base on encoding, so lets check the resulting type encoding
+ add_type = (encoding == type_sp->GetEncoding());
+ if (add_type)
+ {
+ // The type encoding matches, if this is a user defined type, lets
+ // make sure the exact user define type uid matches if one was provided
+ if (encoding == Type::user_defined_type && udt_uid != LLDB_INVALID_UID)
+ {
+ UserDefType* udt = type_sp->GetUserDefinedType().get();
+ if (udt)
+ add_type = udt->UserDefinedTypeUID() == udt_uid;
+ }
+ }
+ }
+ // Add the type to our list as long as everything matched
+ if (add_type)
+ {
+ types.InsertUnique(type_sp);
+ if (++num_matches >= max_matches)
+ break;
+ }
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return types.Size() - original_size;
+}
+
+#endif
+
+
+size_t
+SymbolFileDWARF::ParseChildParameters
+(
+ const SymbolContext& sc,
+ TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ TypeList* type_list,
+ std::vector<void *>& function_param_types,
+ std::vector<clang::ParmVarDecl*>& function_param_decls
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t count = 0;
+ const DWARFDebugInfoEntry *die;
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_formal_parameter:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ Declaration decl;
+ dw_offset_t param_type_die_offset = DW_INVALID_OFFSET;
+ // one of None, Auto, Register, Extern, Static, PrivateExtern
+
+ clang::VarDecl::StorageClass storage = clang::VarDecl::None;
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: param_type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_location:
+ // if (form_value.BlockData())
+ // {
+ // const DataExtractor& debug_info_data = debug_info();
+ // uint32_t block_length = form_value.Unsigned();
+ // DataExtractor location(debug_info_data, form_value.BlockData() - debug_info_data.GetDataStart(), block_length);
+ // }
+ // else
+ // {
+ // }
+ // break;
+ case DW_AT_artificial:
+ case DW_AT_const_value:
+ case DW_AT_default_value:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_is_optional:
+ case DW_AT_segment:
+ case DW_AT_variable_parameter:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ Type *dc_type = ResolveTypeUID(param_type_die_offset);
+ if (dc_type)
+ {
+ function_param_types.push_back (dc_type->GetOpaqueClangQualType());
+
+ clang::ParmVarDecl *param_var_decl = type_list->GetClangASTContext().CreateParmeterDeclaration (name, dc_type->GetOpaqueClangQualType(), storage);
+ assert(param_var_decl);
+ function_param_decls.push_back(param_var_decl);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return count;
+}
+
+size_t
+SymbolFileDWARF::ParseChildEnumerators
+(
+ const SymbolContext& sc,
+ TypeSP& type_sp,
+ void * enumerator_qual_type,
+ uint32_t enumerator_byte_size,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t enumerators_added = 0;
+ const DWARFDebugInfoEntry *die;
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+ if (tag == DW_TAG_enumerator)
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_child_attributes > 0)
+ {
+ const char *name = NULL;
+ bool got_value = false;
+ int64_t enum_value = 0;
+ Declaration decl;
+
+ uint32_t i;
+ for (i=0; i<num_child_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_const_value:
+ got_value = true;
+ enum_value = form_value.Unsigned();
+ break;
+
+ case DW_AT_name:
+ name = form_value.AsCString(&get_debug_str_data());
+ break;
+
+ case DW_AT_description:
+ default:
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ if (name && name[0] && got_value)
+ {
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+ type_list->GetClangASTContext().AddEnumerationValueToEnumerationType (type_sp->GetOpaqueClangQualType(), enumerator_qual_type, decl, name, enum_value, enumerator_byte_size * 8);
+ ++enumerators_added;
+ }
+ }
+ }
+ }
+ return enumerators_added;
+}
+
+void
+SymbolFileDWARF::ParseChildArrayInfo
+(
+ const SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ int64_t& first_index,
+ std::vector<uint64_t>& element_orders,
+ uint32_t& byte_stride,
+ uint32_t& bit_stride
+)
+{
+ if (parent_die == NULL)
+ return;
+
+ const DWARFDebugInfoEntry *die;
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_enumerator:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_child_attributes > 0)
+ {
+ const char *name = NULL;
+ bool got_value = false;
+ int64_t enum_value = 0;
+
+ uint32_t i;
+ for (i=0; i<num_child_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_const_value:
+ got_value = true;
+ enum_value = form_value.Unsigned();
+ break;
+
+ case DW_AT_name:
+ name = form_value.AsCString(&get_debug_str_data());
+ break;
+
+ case DW_AT_description:
+ default:
+ case DW_AT_decl_file:
+ case DW_AT_decl_line:
+ case DW_AT_decl_column:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_subrange_type:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_child_attributes > 0)
+ {
+ const char *name = NULL;
+ bool got_value = false;
+ uint64_t byte_size = 0;
+ int64_t enum_value = 0;
+ uint64_t num_elements = 0;
+ uint64_t lower_bound = 0;
+ uint64_t upper_bound = 0;
+ uint32_t i;
+ for (i=0; i<num_child_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_const_value:
+ got_value = true;
+ enum_value = form_value.Unsigned();
+ break;
+
+ case DW_AT_name:
+ name = form_value.AsCString(&get_debug_str_data());
+ break;
+
+ case DW_AT_count:
+ num_elements = form_value.Unsigned();
+ break;
+
+ case DW_AT_bit_stride:
+ bit_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_byte_stride:
+ byte_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_byte_size:
+ byte_size = form_value.Unsigned();
+ break;
+
+ case DW_AT_lower_bound:
+ lower_bound = form_value.Unsigned();
+ break;
+
+ case DW_AT_upper_bound:
+ upper_bound = form_value.Unsigned();
+ break;
+
+ default:
+ //printf("0x%8.8x: %-30s skipping attribute at 0x%8.8x: %s\n", die->GetOffset(), DW_TAG_value_to_name(tag), attributes.die_offsets[i], DW_AT_value_to_name(attr)); // remove this, debug only
+
+ case DW_AT_abstract_origin:
+ case DW_AT_accessibility:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_sibling:
+ case DW_AT_threads_scaled:
+ case DW_AT_type:
+ case DW_AT_visibility:
+ break;
+ }
+ }
+ }
+
+ if (upper_bound > lower_bound)
+ num_elements = upper_bound - lower_bound + 1;
+
+ if (num_elements > 0)
+ element_orders.push_back (num_elements);
+ }
+ }
+ break;
+ }
+ }
+}
+
+Type*
+SymbolFileDWARF::GetUniquedTypeForDIEOffset(dw_offset_t type_die_offset, TypeSP& owning_type_sp, int32_t child_type, uint32_t idx, bool safe)
+{
+ if (type_die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* type_die = DebugInfo()->GetDIEPtr(type_die_offset, &cu_sp);
+ assert(type_die != NULL);
+ GetTypeForDIE(cu_sp.get(), type_die, owning_type_sp, child_type, idx);
+ // Return the uniqued type if there is one
+ Type* type = (Type*)type_die->GetUserData();
+ if (type == DIE_IS_BEING_PARSED && safe)
+ return NULL;
+ return type;
+ }
+ return NULL;
+}
+
+TypeSP
+SymbolFileDWARF::GetTypeForDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry* die, TypeSP& owning_type_sp, int32_t child_type, uint32_t idx)
+{
+ TypeSP type_sp;
+ if (die != NULL)
+ {
+ assert(cu != NULL);
+ Type *type_ptr = (Type *)die->GetUserData();
+ if (type_ptr == NULL)
+ {
+ SymbolContext sc(GetCompUnitForDWARFCompUnit(cu));
+ bool type_is_new = false;
+ type_sp = ParseType(sc, cu, die, type_is_new);
+ type_ptr = (Type *)die->GetUserData();
+ if (owning_type_sp.get() == NULL)
+ owning_type_sp = type_sp;
+ }
+ else if (type_ptr != DIE_IS_BEING_PARSED)
+ {
+ // Grab the existing type from the master types lists
+ type_sp = m_obj_file->GetModule()->GetTypeList()->FindType(type_ptr->GetID());
+ }
+
+ }
+ return type_sp;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIEOffset (dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp);
+ return GetClangDeclContextForDIE (cu_sp.get(), die);
+ }
+ return NULL;
+}
+
+
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIE (const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+{
+ DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die);
+ if (pos != m_die_to_decl_ctx.end())
+ return pos->second;
+
+ while (die != NULL)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_namespace:
+ {
+ const char *namespace_name = die->GetAttributeValueAsString(this, cu, DW_AT_name, NULL);
+ if (namespace_name)
+ {
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+ assert(type_list);
+ Declaration decl; // TODO: fill in the decl object
+ clang::NamespaceDecl *namespace_decl = type_list->GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, decl, GetClangDeclContextForDIE (cu, die->GetParent()));
+ if (namespace_decl)
+ m_die_to_decl_ctx[die] = (clang::DeclContext*)namespace_decl;
+ return namespace_decl;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ clang::DeclContext *decl_ctx;
+ decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, cu, DW_AT_specification, DW_INVALID_OFFSET));
+ if (decl_ctx)
+ return decl_ctx;
+
+ decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET));
+ if (decl_ctx)
+ return decl_ctx;
+
+ die = die->GetParent();
+ }
+ return NULL;
+}
+
+TypeSP
+SymbolFileDWARF::ParseType(const SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool &type_is_new)
+{
+ TypeSP type_sp;
+
+ uint32_t accessibility = clang::AS_none;
+ if (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+ if (die->GetUserData() == NULL)
+ {
+ type_is_new = true;
+
+ bool is_forward_declaration = false;
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *type_name_cstr = NULL;
+ ConstString type_name_dbstr;
+ Type::EncodingUIDType encoding_uid_type = Type::eIsTypeWithUID;
+ void *clang_type = NULL;
+
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+ dw_attr_t attr;
+
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ Declaration decl;
+ uint32_t encoding = 0;
+ size_t byte_size = 0;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_dbstr.SetCString(type_name_cstr);
+ break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_encoding: encoding = form_value.Unsigned(); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ switch (tag)
+ {
+ default:
+ case DW_TAG_base_type:
+ clang_type = type_list->GetClangASTContext().GetBuiltinTypeForDWARFEncodingAndBitSize (type_name_cstr, encoding, byte_size * 8);
+ break;
+
+ case DW_TAG_pointer_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::ePointerToTypeWithUID;
+ break;
+
+ case DW_TAG_reference_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eLValueReferenceToTypeWithUID;
+ break;
+
+ case DW_TAG_typedef:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eTypedefToTypeWithUID;
+ break;
+
+ case DW_TAG_const_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eIsConstTypeWithUID; //ClangASTContext::AddConstModifier (clang_type);
+ break;
+
+ case DW_TAG_restrict_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eIsRestrictTypeWithUID; //ClangASTContext::AddRestrictModifier (clang_type);
+ break;
+
+ case DW_TAG_volatile_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eIsVolatileTypeWithUID; //ClangASTContext::AddVolatileModifier (clang_type);
+ break;
+ }
+
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, encoding_uid, encoding_uid_type, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+
+
+// Type* encoding_type = GetUniquedTypeForDIEOffset(encoding_uid, type_sp, NULL, 0, 0, false);
+// if (encoding_type != NULL)
+// {
+// if (encoding_type != DIE_IS_BEING_PARSED)
+// type_sp->SetEncodingType(encoding_type);
+// else
+// m_indirect_fixups.push_back(type_sp.get());
+// }
+ }
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ size_t byte_size = 0;
+ //bool struct_is_class = false;
+ Declaration decl;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_dbstr.SetCString(type_name_cstr);
+ break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break; break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break;
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ int tag_decl_kind = -1;
+ int default_accessibility = clang::AS_none;
+ if (tag == DW_TAG_structure_type)
+ {
+ tag_decl_kind = clang::TTK_Struct;
+ default_accessibility = clang::AS_public;
+ }
+ else if (tag == DW_TAG_union_type)
+ {
+ tag_decl_kind = clang::TTK_Union;
+ default_accessibility = clang::AS_public;
+ }
+ else if (tag == DW_TAG_class_type)
+ {
+ tag_decl_kind = clang::TTK_Class;
+ default_accessibility = clang::AS_private;
+ }
+
+ assert (tag_decl_kind != -1);
+ clang_type = type_list->GetClangASTContext().CreateRecordType (type_name_cstr, tag_decl_kind, GetClangDeclContextForDIE (dwarf_cu, die));
+
+ m_die_to_decl_ctx[die] = ClangASTContext::GetDeclContextForType (clang_type);
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+
+// assert(type_sp.get());
+// if (accessibility)
+// type_sp->SetAccess(accessibility);
+//
+ type_list->GetClangASTContext().StartTagDeclarationDefinition (clang_type);
+ if (die->HasChildren())
+ {
+ std::vector<clang::CXXBaseSpecifier *> base_classes;
+ std::vector<int> member_accessibilities;
+ bool is_a_class = false;
+ ParseChildMembers(sc, type_sp, dwarf_cu, die, base_classes, member_accessibilities, default_accessibility, is_a_class);
+ // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we
+ // need to tell the clang type it is actually a class.
+ if (is_a_class && tag_decl_kind != clang::TTK_Class)
+ type_list->GetClangASTContext().SetTagTypeKind (clang_type, clang::TTK_Class);
+
+ // Since DW_TAG_structure_type gets used for both classes
+ // and structures, we may need to set any DW_TAG_member
+ // fields to have a "private" access if none was specified.
+ // When we parsed the child members we tracked that actual
+ // accessibility value for each DW_TAG_member in the
+ // "member_accessibilities" array. If the value for the
+ // member is zero, then it was set to the "default_accessibility"
+ // which for structs was "public". Below we correct this
+ // by setting any fields to "private" that weren't correctly
+ // set.
+ if (is_a_class && !member_accessibilities.empty())
+ {
+ // This is a class and all members that didn't have
+ // their access specified are private.
+ type_list->GetClangASTContext().SetDefaultAccessForRecordFields (clang_type, clang::AS_private, member_accessibilities.data(), member_accessibilities.size());
+ }
+
+ if (!base_classes.empty())
+ {
+ type_list->GetClangASTContext().SetBaseClassesForClassType (clang_type, base_classes.data(), base_classes.size());
+ }
+ }
+ type_list->GetClangASTContext().CompleteTagDeclarationDefinition (clang_type);
+ }
+ break;
+
+ case DW_TAG_enumeration_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ size_t byte_size = 0;
+ lldb::user_id_t encoding_uid = DW_INVALID_OFFSET;
+ Declaration decl;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_dbstr.SetCString(type_name_cstr);
+ break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break;
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_stride:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ clang_type = type_list->GetClangASTContext().CreateEnumerationType(decl, type_name_cstr);
+ m_die_to_decl_ctx[die] = ClangASTContext::GetDeclContextForType (clang_type);
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, encoding_uid, Type::eIsTypeWithUID, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+
+ if (die->HasChildren())
+ {
+ type_list->GetClangASTContext().StartTagDeclarationDefinition (clang_type);
+ void *enumerator_qual_type = type_list->GetClangASTContext().GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, DW_ATE_signed, byte_size * 8);
+ ParseChildEnumerators(sc, type_sp, enumerator_qual_type, byte_size, dwarf_cu, die);
+ type_list->GetClangASTContext().CompleteTagDeclarationDefinition (clang_type);
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ const char *mangled = NULL;
+ dw_offset_t type_die_offset = DW_INVALID_OFFSET;
+ Declaration decl;
+ bool isVariadic = false;
+ bool is_inline = false;
+ unsigned type_quals = 0;
+ clang::FunctionDecl::StorageClass storage = clang::FunctionDecl::None;//, Extern, Static, PrivateExtern
+
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_dbstr.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break;
+ case DW_AT_external:
+ if (form_value.Unsigned())
+ {
+ if (storage == clang::FunctionDecl::None)
+ storage = clang::FunctionDecl::Extern;
+ else
+ storage = clang::FunctionDecl::PrivateExtern;
+ }
+ break;
+ case DW_AT_inline:
+ is_inline = form_value.Unsigned() != 0;
+ break;
+
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_address_class:
+ case DW_AT_artificial:
+ case DW_AT_calling_convention:
+ case DW_AT_data_location:
+ case DW_AT_elemental:
+ case DW_AT_entry_pc:
+ case DW_AT_explicit:
+ case DW_AT_frame_base:
+ case DW_AT_high_pc:
+ case DW_AT_low_pc:
+ case DW_AT_object_pointer:
+ case DW_AT_prototyped:
+ case DW_AT_pure:
+ case DW_AT_ranges:
+ case DW_AT_recursive:
+ case DW_AT_return_addr:
+ case DW_AT_segment:
+ case DW_AT_specification:
+ case DW_AT_start_scope:
+ case DW_AT_static_link:
+ case DW_AT_trampoline:
+ case DW_AT_visibility:
+ case DW_AT_virtuality:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_abstract_origin:
+ case DW_AT_description:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ void *return_clang_type = NULL;
+ Type *func_type = ResolveTypeUID(type_die_offset);
+ if (func_type)
+ return_clang_type = func_type->GetOpaqueClangQualType();
+ else
+ return_clang_type = type_list->GetClangASTContext().GetVoidBuiltInType();
+
+ std::vector<void *> function_param_types;
+ std::vector<clang::ParmVarDecl*> function_param_decls;
+
+ // Parse the function children for the parameters
+ ParseChildParameters(sc, type_sp, dwarf_cu, die, type_list, function_param_types, function_param_decls);
+
+ clang_type = type_list->GetClangASTContext().CreateFunctionType (return_clang_type, &function_param_types[0], function_param_types.size(), isVariadic, type_quals);
+ if (type_name_cstr)
+ {
+ clang::FunctionDecl *function_decl = type_list->GetClangASTContext().CreateFunctionDeclaration (type_name_cstr, clang_type, storage, is_inline);
+ // Add the decl to our DIE to decl context map
+ assert (function_decl);
+ m_die_to_decl_ctx[die] = function_decl;
+ if (!function_param_decls.empty())
+ type_list->GetClangASTContext().SetFunctionParameters (function_decl, function_param_decls.data(), function_param_decls.size());
+ }
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, 0, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+ assert(type_sp.get());
+ }
+ }
+ break;
+
+ case DW_TAG_array_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ size_t byte_size = 0;
+ lldb::user_id_t type_die_offset = DW_INVALID_OFFSET;
+ Declaration decl;
+ int64_t first_index = 0;
+ uint32_t byte_stride = 0;
+ uint32_t bit_stride = 0;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_dbstr.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_byte_stride: byte_stride = form_value.Unsigned(); break;
+ case DW_AT_bit_stride: bit_stride = form_value.Unsigned(); break;
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break;
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_ordering:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ Type *element_type = ResolveTypeUID(type_die_offset);
+
+ if (element_type)
+ {
+ std::vector<uint64_t> element_orders;
+ ParseChildArrayInfo(sc, dwarf_cu, die, first_index, element_orders, byte_stride, bit_stride);
+ if (byte_stride == 0 && bit_stride == 0)
+ byte_stride = element_type->GetByteSize();
+ void *array_element_type = element_type->GetOpaqueClangQualType();
+ uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride;
+ uint64_t num_elements = 0;
+ std::vector<uint64_t>::const_reverse_iterator pos;
+ std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend();
+ for (pos = element_orders.rbegin(); pos != end; ++pos)
+ {
+ num_elements = *pos;
+ clang_type = type_list->GetClangASTContext().CreateArrayType (array_element_type, num_elements, num_elements * array_element_bit_stride);
+ array_element_type = clang_type;
+ array_element_bit_stride = array_element_bit_stride * num_elements;
+ }
+ ConstString empty_name;
+ type_sp.reset( new Type(die->GetOffset(), this, empty_name, array_element_bit_stride / 8, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type));
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (type_sp.get())
+ {
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t sc_parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+
+ SymbolContextScope * symbol_context_scope = NULL;
+ if (sc_parent_tag == DW_TAG_compile_unit)
+ {
+ symbol_context_scope = sc.comp_unit;
+ }
+ else if (sc.function != NULL)
+ {
+ symbol_context_scope = sc.function->GetBlocks(true).GetBlockByID(sc_parent_die->GetOffset());
+ if (symbol_context_scope == NULL)
+ symbol_context_scope = sc.function;
+ }
+
+ if (symbol_context_scope != NULL)
+ {
+ type_sp->SetSymbolContextScope(symbol_context_scope);
+ }
+
+// if (udt_sp.get())
+// {
+// if (is_forward_declaration)
+// udt_sp->GetFlags().Set(UserDefType::flagIsForwardDefinition);
+// type_sp->SetUserDefinedType(udt_sp);
+// }
+
+ if (type_sp.unique())
+ {
+ // We are ready to put this type into the uniqued list up at the module level
+ TypeSP uniqued_type_sp(m_obj_file->GetModule()->GetTypeList()->InsertUnique(type_sp));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(uniqued_type_sp.get());
+
+ type_sp = uniqued_type_sp;
+ }
+ }
+ }
+ else
+ {
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_array_type:
+ {
+ Type *existing_type = (Type*)die->GetUserData();
+ if (existing_type != DIE_IS_BEING_PARSED)
+ {
+ type_sp = m_obj_file->GetModule()->GetTypeList()->FindType(existing_type->GetID());
+ }
+ }
+ break;
+ default:
+ //assert(!"invalid type tag...");
+ break;
+ }
+ }
+ }
+ return type_sp;
+}
+
+size_t
+SymbolFileDWARF::ParseTypes (const SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children)
+{
+ size_t types_added = 0;
+ while (die != NULL)
+ {
+ bool type_is_new = false;
+ if (ParseType(sc, dwarf_cu, die, type_is_new).get())
+ {
+ if (type_is_new)
+ ++types_added;
+ }
+
+ if (parse_children && die->HasChildren())
+ {
+ if (die->Tag() == DW_TAG_subprogram)
+ {
+ SymbolContext child_sc(sc);
+ child_sc.function = sc.comp_unit->FindFunctionByUID(die->GetOffset()).get();
+ types_added += ParseTypes(child_sc, dwarf_cu, die->GetFirstChild(), true, true);
+ }
+ else
+ types_added += ParseTypes(sc, dwarf_cu, die->GetFirstChild(), true, true);
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+ return types_added;
+}
+
+
+size_t
+SymbolFileDWARF::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ assert(sc.comp_unit && sc.function);
+ size_t functions_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ if (dwarf_cu)
+ {
+ dw_offset_t function_die_offset = sc.function->GetID();
+ const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(function_die_offset);
+ if (function_die)
+ {
+ ParseFunctionBlocks(sc, Block::RootID, dwarf_cu, function_die, LLDB_INVALID_ADDRESS, false, true);
+ }
+ }
+
+ return functions_added;
+}
+
+
+size_t
+SymbolFileDWARF::ParseTypes (const SymbolContext &sc)
+{
+ // At least a compile unit must be valid
+ assert(sc.comp_unit);
+ size_t types_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ if (dwarf_cu)
+ {
+ if (sc.function)
+ {
+ dw_offset_t function_die_offset = sc.function->GetID();
+ const DWARFDebugInfoEntry *func_die = dwarf_cu->GetDIEPtr(function_die_offset);
+ if (func_die && func_die->HasChildren())
+ {
+ types_added = ParseTypes(sc, dwarf_cu, func_die->GetFirstChild(), true, true);
+ }
+ }
+ else
+ {
+ const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->DIE();
+ if (dwarf_cu_die && dwarf_cu_die->HasChildren())
+ {
+ types_added = ParseTypes(sc, dwarf_cu, dwarf_cu_die->GetFirstChild(), true, true);
+ }
+ }
+ }
+
+ return types_added;
+}
+
+size_t
+SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc)
+{
+ if (sc.comp_unit != NULL)
+ {
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+
+ if (dwarf_cu == NULL)
+ return 0;
+
+ if (sc.function)
+ {
+ const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(sc.function->GetID());
+ return ParseVariables(sc, dwarf_cu, function_die->GetFirstChild(), true, true);
+ }
+ else if (sc.comp_unit)
+ {
+ uint32_t vars_added = 0;
+ VariableListSP variables (sc.comp_unit->GetVariableList(false));
+
+ if (variables.get() == NULL)
+ {
+ variables.reset(new VariableList());
+ sc.comp_unit->SetVariableList(variables);
+
+ // Index if we already haven't to make sure the compile units
+ // get indexed and make their global DIE index list
+ if (!m_indexed)
+ Index ();
+
+ const size_t num_globals = dwarf_cu->GetNumGlobals();
+ for (size_t idx=0; idx<num_globals; ++idx)
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, dwarf_cu->GetGlobalDIEAtIndex (idx)));
+ if (var_sp)
+ {
+ variables->AddVariable(var_sp);
+ ++vars_added;
+ }
+ }
+ }
+ return vars_added;
+ }
+ }
+ return 0;
+}
+
+
+VariableSP
+SymbolFileDWARF::ParseVariableDIE
+(
+ const SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die
+)
+{
+
+ VariableSP var_sp;
+
+ const dw_tag_t tag = die->Tag();
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ Declaration decl;
+ uint32_t i;
+ TypeSP type_sp;
+ Type *var_type = NULL;
+ DWARFExpression location;
+ bool is_external = false;
+ bool is_artificial = false;
+ uint32_t accessibility = clang::AS_none;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: var_type = GetUniquedTypeForDIEOffset(form_value.Reference(dwarf_cu), type_sp, 0, 0, false); break;
+ case DW_AT_external: is_external = form_value.Unsigned() != 0; break;
+ case DW_AT_location:
+ {
+ if (form_value.BlockData())
+ {
+ const DataExtractor& debug_info_data = get_debug_info_data();
+
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ location.SetOpcodeData(get_debug_info_data(), block_offset, block_length, NULL);
+ }
+ else
+ {
+ const DataExtractor& debug_loc_data = get_debug_loc_data();
+ const dw_offset_t debug_loc_offset = form_value.Unsigned();
+
+ size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset);
+ if (loc_list_length > 0)
+ {
+ Address base_address(dwarf_cu->GetBaseAddress(), m_obj_file->GetSectionList());
+ location.SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length, &base_address);
+ }
+ }
+ }
+ break;
+
+ case DW_AT_artificial: is_artificial = form_value.Unsigned() != 0; break;
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_const_value:
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_segment:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ case DW_AT_specification:
+ break;
+ }
+ }
+ }
+
+ if (location.IsValid())
+ {
+ assert(var_type != DIE_IS_BEING_PARSED);
+
+ ConstString var_name(name);
+
+ ValueType scope = eValueTypeInvalid;
+
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+
+ if (tag == DW_TAG_formal_parameter)
+ scope = eValueTypeVariableArgument;
+ else if (is_external || parent_tag == DW_TAG_compile_unit)
+ scope = eValueTypeVariableGlobal;
+ else
+ scope = eValueTypeVariableLocal;
+
+ SymbolContextScope * symbol_context_scope = NULL;
+ if (parent_tag == DW_TAG_compile_unit)
+ {
+ symbol_context_scope = sc.comp_unit;
+ }
+ else if (sc.function != NULL)
+ {
+ symbol_context_scope = sc.function->GetBlocks(true).GetBlockByID(sc_parent_die->GetOffset());
+ if (symbol_context_scope == NULL)
+ symbol_context_scope = sc.function;
+ }
+
+ assert(symbol_context_scope != NULL);
+ var_sp.reset (new Variable(die->GetOffset(),
+ var_name,
+ var_type,
+ scope,
+ symbol_context_scope,
+ &decl,
+ location,
+ is_external,
+ is_artificial));
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(var_sp.get());
+ }
+ }
+ return var_sp;
+}
+
+size_t
+SymbolFileDWARF::ParseVariables
+(
+ const SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *orig_die,
+ bool parse_siblings,
+ bool parse_children,
+ VariableList* cc_variable_list
+)
+{
+ if (orig_die == NULL)
+ return 0;
+
+ size_t vars_added = 0;
+ const DWARFDebugInfoEntry *die = orig_die;
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+ VariableListSP variables;
+ switch (parent_tag)
+ {
+ case DW_TAG_compile_unit:
+ if (sc.comp_unit != NULL)
+ {
+ variables = sc.comp_unit->GetVariableList(false);
+ if (variables.get() == NULL)
+ {
+ variables.reset(new VariableList());
+ sc.comp_unit->SetVariableList(variables);
+ }
+ }
+ else
+ {
+ assert(!"Parent DIE was a compile unit, yet we don't have a valid compile unit in the symbol context...");
+ vars_added = 0;
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ if (sc.function != NULL)
+ {
+ // Check to see if we already have parsed the variables for the given scope
+ variables = sc.function->GetBlocks(true).GetVariableList(sc_parent_die->GetOffset(), false, false);
+ if (variables.get() == NULL)
+ {
+ variables.reset(new VariableList());
+ sc.function->GetBlocks(true).SetVariableList(sc_parent_die->GetOffset(), variables);
+ }
+ }
+ else
+ {
+ assert(!"Parent DIE was a function or block, yet we don't have a function in the symbol context...");
+ vars_added = 0;
+ }
+ break;
+
+ default:
+ assert(!"Didn't find appropriate parent DIE for variable list...");
+ break;
+ }
+
+ // We need to have a variable list at this point that we can add variables to
+ assert(variables.get());
+
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ // Check to see if we have already parsed this variable or constant?
+ if (die->GetUserData() == NULL)
+ {
+ // We haven't already parsed it, lets do that now.
+ if ((tag == DW_TAG_variable) ||
+ (tag == DW_TAG_constant) ||
+ (tag == DW_TAG_formal_parameter && sc.function))
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die));
+ if (var_sp)
+ {
+ variables->AddVariable(var_sp);
+ ++vars_added;
+ }
+ }
+ }
+
+ bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram);
+
+ if (!skip_children && parse_children && die->HasChildren())
+ {
+ vars_added += ParseVariables(sc, dwarf_cu, die->GetFirstChild(), true, true);
+ //vars_added += ParseVariables(sc, dwarf_cu, die->GetFirstChild(), parse_siblings, parse_children);
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+
+ if (cc_variable_list)
+ {
+ cc_variable_list->AddVariables(variables.get());
+ }
+
+ return vars_added;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolFileDWARF::GetPluginName()
+{
+ return "SymbolFileDWARF";
+}
+
+const char *
+SymbolFileDWARF::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileDWARF::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolFileDWARF::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolFileDWARF::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
new file mode 100644
index 0000000..95545a4
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -0,0 +1,331 @@
+//===-- SymbolFileDWARF.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_SymbolFileDWARF_h_
+#define liblldb_SymbolFileDWARF_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <memory>
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+// Project includes
+#include "DWARFDefines.h"
+
+
+//----------------------------------------------------------------------
+// Forward Declarations for this DWARF plugin
+//----------------------------------------------------------------------
+class DWARFAbbreviationDeclaration;
+class DWARFAbbreviationDeclarationSet;
+class DWARFCompileUnit;
+class DWARFDebugAbbrev;
+class DWARFDebugAranges;
+class DWARFDebugInfo;
+class DWARFDebugInfoEntry;
+class DWARFDebugLine;
+class DWARFDebugPubnames;
+class DWARFDebugRanges;
+class DWARFDIECollection;
+class DWARFFormValue;
+
+class SymbolFileDWARF : public lldb_private::SymbolFile
+{
+public:
+ friend class SymbolFileDWARFDebugMap;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile*
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileDWARF(lldb_private::ObjectFile* ofile);
+ virtual ~SymbolFileDWARF();
+
+ virtual uint32_t GetAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index);
+
+ virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList& support_files);
+ virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type* ResolveTypeUID(lldb::user_id_t type_uid);
+ virtual clang::DeclContext* GetClangDeclContextForTypeUID (lldb::user_id_t type_uid);
+
+ virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindGlobalVariables(const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindGlobalVariables(const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindFunctions(const lldb_private::ConstString &name, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions(const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list);
+// virtual uint32_t FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+// virtual uint32_t FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+ // Approach 2 - count + accessor
+ // Index compile units would scan the initial compile units and register
+ // them with the module. This would only be done on demand if and only if
+ // the compile units were needed.
+ //virtual size_t GetCompUnitCount() = 0;
+ //virtual CompUnitSP GetCompUnitAtIndex(size_t cu_idx) = 0;
+
+ const lldb_private::DataExtractor& get_debug_abbrev_data();
+ const lldb_private::DataExtractor& get_debug_aranges_data();
+ const lldb_private::DataExtractor& get_debug_frame_data();
+ const lldb_private::DataExtractor& get_debug_info_data();
+ const lldb_private::DataExtractor& get_debug_line_data();
+ const lldb_private::DataExtractor& get_debug_loc_data();
+ const lldb_private::DataExtractor& get_debug_macinfo_data();
+ const lldb_private::DataExtractor& get_debug_pubnames_data();
+ const lldb_private::DataExtractor& get_debug_pubtypes_data();
+ const lldb_private::DataExtractor& get_debug_ranges_data();
+ const lldb_private::DataExtractor& get_debug_str_data();
+
+ DWARFDebugAbbrev* DebugAbbrev();
+ const DWARFDebugAbbrev* DebugAbbrev() const;
+
+ DWARFDebugAranges* DebugAranges();
+ const DWARFDebugAranges*DebugAranges() const;
+
+ DWARFDebugInfo* DebugInfo();
+ const DWARFDebugInfo* DebugInfo() const;
+
+// These shouldn't be used unless we want to dump the DWARF line tables.
+// DWARFDebugLine* DebugLine();
+// const DWARFDebugLine* DebugLine() const;
+
+// DWARFDebugPubnames* DebugPubnames();
+// const DWARFDebugPubnames* DebugPubnames() const;
+//
+// DWARFDebugPubnames* DebugPubBaseTypes();
+// const DWARFDebugPubnames* DebugPubBaseTypes() const;
+//
+// DWARFDebugPubnames* DebugPubtypes();
+// const DWARFDebugPubnames* DebugPubtypes() const;
+
+ DWARFDebugRanges* DebugRanges();
+ const DWARFDebugRanges* DebugRanges() const;
+
+ const lldb_private::DataExtractor&
+ GetCachedSectionData (uint32_t got_flag, const lldb_private::ConstString §ion_name, lldb_private::DataExtractor &data);
+
+ static bool SupportedVersion(uint16_t version);
+
+ clang::DeclContext *
+ GetClangDeclContextForDIE (const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die);
+
+ clang::DeclContext *
+ GetClangDeclContextForDIEOffset (dw_offset_t die_offset);
+
+ lldb_private::Flags&
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags&
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+protected:
+
+ enum
+ {
+ flagsGotDebugAbbrevData = (1 << 0),
+ flagsGotDebugArangesData = (1 << 1),
+ flagsGotDebugFrameData = (1 << 2),
+ flagsGotDebugInfoData = (1 << 3),
+ flagsGotDebugLineData = (1 << 4),
+ flagsGotDebugLocData = (1 << 5),
+ flagsGotDebugMacInfoData = (1 << 6),
+ flagsGotDebugPubNamesData = (1 << 7),
+ flagsGotDebugPubTypesData = (1 << 8),
+ flagsGotDebugRangesData = (1 << 9),
+ flagsGotDebugStrData = (1 << 10),
+ // True if this is a .o file used when resolving a N_OSO entry with
+ // debug maps.
+ flagsDWARFIsOSOForDebugMap = (1 << 16)
+ };
+
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileDWARF);
+ bool ParseCompileUnit(DWARFCompileUnit* cu, lldb::CompUnitSP& compile_unit_sp);
+ DWARFCompileUnit* GetDWARFCompileUnitForUID(lldb::user_id_t cu_uid);
+ DWARFCompileUnit* GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu);
+ lldb_private::CompileUnit* GetCompUnitForDWARFCompUnit(DWARFCompileUnit* cu, uint32_t cu_idx = UINT_MAX);
+ bool GetFunction (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* func_die, lldb_private::SymbolContext& sc);
+ lldb_private::Function * ParseCompileUnitFunction (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die);
+ size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc,
+ lldb::user_id_t parentBlockID,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb::addr_t subprogram_low_pc,
+ bool parse_siblings,
+ bool parse_children);
+ size_t ParseTypes (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children);
+ lldb::TypeSP ParseType (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool &type_is_new);
+
+ lldb::VariableSP ParseVariableDIE(
+ const lldb_private::SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die);
+
+ size_t ParseVariables(
+ const lldb_private::SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ bool parse_siblings,
+ bool parse_children,
+ lldb_private::VariableList* cc_variable_list = NULL);
+
+ size_t ParseChildMembers(
+ const lldb_private::SymbolContext& sc,
+ lldb::TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ int &default_accessibility,
+ bool &is_a_class);
+
+ size_t ParseChildParameters(
+ const lldb_private::SymbolContext& sc,
+ lldb::TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ lldb_private::TypeList* type_list,
+ std::vector<void *>& function_args,
+ std::vector<clang::ParmVarDecl*>& function_param_decls);
+
+ size_t ParseChildEnumerators(
+ const lldb_private::SymbolContext& sc,
+ lldb::TypeSP& type_sp,
+ void *enumerator_qual_type,
+ uint32_t enumerator_byte_size,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *enum_die);
+
+ void ParseChildArrayInfo(
+ const lldb_private::SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ int64_t& first_index,
+ std::vector<uint64_t>& element_orders,
+ uint32_t& byte_stride,
+ uint32_t& bit_stride);
+
+ lldb_private::Type* GetUniquedTypeForDIEOffset(dw_offset_t type_die_offset, lldb::TypeSP& owning_type_sp, int32_t child_type, uint32_t idx, bool safe);
+ lldb::TypeSP GetTypeForDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry* die, lldb::TypeSP& owning_type_sp, int32_t child_type, uint32_t idx);
+// uint32_t FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types);
+
+ void Index();
+
+ lldb_private::Flags m_flags;
+ lldb_private::DataExtractor m_dwarf_data;
+ lldb_private::DataExtractor m_data_debug_abbrev;
+ lldb_private::DataExtractor m_data_debug_aranges;
+ lldb_private::DataExtractor m_data_debug_frame;
+ lldb_private::DataExtractor m_data_debug_info;
+ lldb_private::DataExtractor m_data_debug_line;
+ lldb_private::DataExtractor m_data_debug_loc;
+ lldb_private::DataExtractor m_data_debug_macinfo;
+ lldb_private::DataExtractor m_data_debug_pubnames;
+ lldb_private::DataExtractor m_data_debug_pubtypes;
+ lldb_private::DataExtractor m_data_debug_ranges;
+ lldb_private::DataExtractor m_data_debug_str;
+
+ // The auto_ptr items below are generated on demand if and when someone accesses
+ // them through a non const version of this class.
+ std::auto_ptr<DWARFDebugAbbrev> m_abbr;
+ std::auto_ptr<DWARFDebugAranges> m_aranges;
+ std::auto_ptr<DWARFDebugInfo> m_info;
+ std::auto_ptr<DWARFDebugLine> m_line;
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_function_die; // All concrete functions
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_inlined_die; // All inlined functions
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_global_die; // Global and static variables
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_type_die; // All type DIE offsets
+ bool m_indexed;
+
+// std::auto_ptr<DWARFDebugPubnames> m_pubnames;
+// std::auto_ptr<DWARFDebugPubnames> m_pubbasetypes; // Just like m_pubtypes, but for DW_TAG_base_type DIEs
+// std::auto_ptr<DWARFDebugPubnames> m_pubtypes;
+ std::auto_ptr<DWARFDebugRanges> m_ranges;
+
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> DIEToDeclContextMap;
+ DIEToDeclContextMap m_die_to_decl_ctx;
+
+// TypeFixupColl m_type_fixups;
+// std::vector<Type*> m_indirect_fixups;
+
+//#define LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST 1
+#if defined(LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST)
+
+ typedef std::map<FileSpec, DWARFDIECollection> FSToDIES;
+ void ShrinkDSYM(CompileUnit *dc_cu, DWARFCompileUnit *dw_cu, const FileSpec& cu_fspec, const FileSpec& base_types_cu_fspec, FSToDIES& fs_to_dies, const DWARFDebugInfoEntry *die);
+#endif
+};
+
+#endif // liblldb_SymbolFileDWARF_h_
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
new file mode 100644
index 0000000..7bf968d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -0,0 +1,873 @@
+//===-- SymbolFileDWARFDebugMap.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARFDebugMap.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "SymbolFileDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SymbolFileDWARFDebugMap::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARFDebugMap::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+SymbolFileDWARFDebugMap::GetPluginNameStatic()
+{
+ return "symbol-file.dwarf2-debugmap";
+}
+
+const char *
+SymbolFileDWARFDebugMap::GetPluginDescriptionStatic()
+{
+ return "DWARF and DWARF3 debug symbol file reader (debug map).";
+}
+
+SymbolFile*
+SymbolFileDWARFDebugMap::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileDWARFDebugMap (obj_file);
+}
+
+
+SymbolFileDWARFDebugMap::SymbolFileDWARFDebugMap (ObjectFile* ofile) :
+ SymbolFile(ofile),
+ m_flags(),
+ m_compile_unit_infos(),
+ m_func_indexes(),
+ m_glob_indexes()
+{
+}
+
+
+SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap()
+{
+}
+
+void
+SymbolFileDWARFDebugMap::InitOSO ()
+{
+ if (m_flags.test(kHaveInitializedOSOs))
+ return;
+
+ m_flags.set(kHaveInitializedOSOs);
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that
+ // then we return the abilities of the first N_OSO's DWARF.
+
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ //StreamFile s(0, 4, eByteOrderHost, stdout);
+ std::vector<uint32_t> oso_indexes;
+ const uint32_t oso_index_count = symtab->AppendSymbolIndexesWithType(eSymbolTypeObjectFile, oso_indexes);
+
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeFunction, m_func_indexes);
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeGlobal, m_glob_indexes);
+
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ symtab->SortSymbolIndexesByValue(m_glob_indexes, true);
+
+ if (oso_index_count > 0)
+ {
+ m_compile_unit_infos.resize(oso_index_count);
+// s.Printf("%s N_OSO symbols:\n", __PRETTY_FUNCTION__);
+// symtab->Dump(&s, oso_indexes);
+
+ for (uint32_t i=0; i<oso_index_count; ++i)
+ {
+ m_compile_unit_infos[i].so_symbol = symtab->SymbolAtIndex(oso_indexes[i] - 1);
+ if (m_compile_unit_infos[i].so_symbol->GetSiblingIndex() == 0)
+ m_compile_unit_infos[i].so_symbol = symtab->SymbolAtIndex(oso_indexes[i] - 2);
+ m_compile_unit_infos[i].oso_symbol = symtab->SymbolAtIndex(oso_indexes[i]);
+ }
+ }
+ }
+}
+
+Module *
+SymbolFileDWARFDebugMap::GetModuleByOSOIndex (uint32_t oso_idx)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ if (oso_idx < cu_count)
+ return GetModuleByCompUnitInfo (&m_compile_unit_infos[oso_idx]);
+ return NULL;
+}
+
+Module *
+SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ if (comp_unit_info->oso_module_sp.get() == NULL)
+ {
+ Symbol *oso_symbol = comp_unit_info->oso_symbol;
+ if (oso_symbol)
+ {
+ FileSpec oso_file_spec(oso_symbol->GetMangled().GetName().AsCString());
+
+ ModuleList::GetSharedModule (oso_file_spec,
+ m_obj_file->GetModule()->GetArchitecture(),
+ NULL, // UUID pointer
+ NULL, // object name
+ 0, // object offset
+ comp_unit_info->oso_module_sp,
+ NULL,
+ NULL);
+ //comp_unit_info->oso_module_sp.reset(new Module (oso_file_spec, m_obj_file->GetModule()->GetArchitecture()));
+ }
+ }
+ return comp_unit_info->oso_module_sp.get();
+}
+
+
+bool
+SymbolFileDWARFDebugMap::GetFileSpecForSO (uint32_t oso_idx, FileSpec &file_spec)
+{
+ if (oso_idx < m_compile_unit_infos.size())
+ {
+ if (!m_compile_unit_infos[oso_idx].so_file)
+ {
+
+ if (m_compile_unit_infos[oso_idx].so_symbol == NULL)
+ return false;
+
+ std::string so_path (m_compile_unit_infos[oso_idx].so_symbol->GetMangled().GetName().AsCString());
+ if (m_compile_unit_infos[oso_idx].so_symbol[1].GetType() == eSymbolTypeSourceFile)
+ so_path += m_compile_unit_infos[oso_idx].so_symbol[1].GetMangled().GetName().AsCString();
+ m_compile_unit_infos[oso_idx].so_file.SetFile(so_path.c_str());
+ }
+ file_spec = m_compile_unit_infos[oso_idx].so_file;
+ return true;
+ }
+ return false;
+}
+
+
+
+ObjectFile *
+SymbolFileDWARFDebugMap::GetObjectFileByOSOIndex (uint32_t oso_idx)
+{
+ Module *oso_module = GetModuleByOSOIndex (oso_idx);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFile (const SymbolContext& sc)
+{
+ CompileUnitInfo *comp_unit_info = GetCompUnitInfo (sc);
+ if (comp_unit_info)
+ return GetSymbolFileByCompUnitInfo (comp_unit_info);
+ return NULL;
+}
+
+ObjectFile *
+SymbolFileDWARFDebugMap::GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileByOSOIndex (uint32_t oso_idx)
+{
+ if (oso_idx < m_compile_unit_infos.size())
+ return GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[oso_idx]);
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ if (comp_unit_info->oso_symbol_vendor == NULL)
+ {
+ ObjectFile *oso_objfile = GetObjectFileByCompUnitInfo (comp_unit_info);
+
+ if (oso_objfile)
+ {
+ comp_unit_info->oso_symbol_vendor = oso_objfile->GetModule()->GetSymbolVendor();
+// SymbolFileDWARF *oso_dwarf = new SymbolFileDWARF(oso_objfile);
+// comp_unit_info->oso_dwarf_sp.reset (oso_dwarf);
+ if (comp_unit_info->oso_symbol_vendor)
+ {
+ // Set a bit that lets this DWARF file know that it is being
+ // used along with a debug map and that it will have the
+ // remapped sections that we do below.
+ ((SymbolFileDWARF *)comp_unit_info->oso_symbol_vendor->GetSymbolFile())->GetFlags().Set(SymbolFileDWARF::flagsDWARFIsOSOForDebugMap);
+ comp_unit_info->debug_map_sections_sp.reset(new SectionList);
+
+ Symtab *exe_symtab = m_obj_file->GetSymtab();
+ Module *oso_module = oso_objfile->GetModule();
+ Symtab *oso_symtab = oso_objfile->GetSymtab();
+//#define DEBUG_OSO_DMAP // Do not check in with this defined...
+#if defined(DEBUG_OSO_DMAP)
+ StreamFile s(stdout);
+ s << "OSO symtab:\n";
+ oso_symtab->Dump(&s, NULL);
+ s << "OSO sections before:\n";
+ oso_objfile->GetSectionList()->Dump(&s, NULL, true);
+#endif
+
+ ///const uint32_t fun_resolve_flags = SymbolContext::Module | eSymbolContextCompUnit | eSymbolContextFunction;
+ //SectionList *oso_sections = oso_objfile->Sections();
+ // Now we need to make sections that map from zero based object
+ // file addresses to where things eneded up in the main executable.
+ uint32_t oso_start_idx = comp_unit_info->oso_symbol->GetID() + 1;
+ const uint32_t oso_end_idx = comp_unit_info->so_symbol->GetSiblingIndex();
+ uint32_t sect_id = 0x10000;
+ for (uint32_t idx = oso_start_idx; idx < oso_end_idx; ++idx)
+ {
+ Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx);
+ if (exe_symbol)
+ {
+ switch (exe_symbol->GetType())
+ {
+ case eSymbolTypeFunction:
+ {
+ // For each N_FUN, or function that we run into in the debug map
+ // we make a new section that we add to the sections found in the
+ // .o file. This new section has the file address set to what the
+ // addresses are in the .o file, and the load address is adjusted
+ // to match where it ended up in the final executable! We do this
+ // before we parse any dwarf info so that when it goes get parsed
+ // all section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable.
+
+ // First we find the original symbol in the .o file's symbol table
+ Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeCode);
+ if (oso_fun_symbol)
+ {
+ // If we found the symbol, then we
+ Section* exe_fun_section = const_cast<Section *>(exe_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ Section* oso_fun_section = const_cast<Section *>(oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ if (oso_fun_section)
+ {
+ // Now we create a section that we will add as a child of the
+ // section in which the .o symbol (the N_FUN) exists.
+
+ // We use the exe_symbol size because the one in the .o file
+ // will just be a symbol with no size, and the exe_symbol
+ // size will reflect any size changes (ppc has been known to
+ // shrink function sizes when it gets rid of jump islands that
+ // aren't needed anymore).
+ SectionSP oso_fun_section_sp (new Section (const_cast<Section *>(oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()),
+ oso_module, // Module (the .o file)
+ sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs
+ exe_symbol->GetMangled().GetName(), // Name the section the same as the symbol for which is was generated!
+ eSectionTypeDebug,
+ oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section
+ exe_symbol->GetByteSize(), // File size (we need the size from the executable)
+ 0, 0, 0));
+
+ oso_fun_section_sp->SetLinkedLocation (exe_fun_section,
+ exe_symbol->GetValue().GetFileAddress() - exe_fun_section->GetFileAddress());
+ oso_fun_section->GetChildren().AddSection(oso_fun_section_sp);
+ comp_unit_info->debug_map_sections_sp->AddSection(oso_fun_section_sp);
+ }
+ }
+ }
+ break;
+
+ case eSymbolTypeGlobal:
+ case eSymbolTypeStatic:
+ {
+ // For each N_GSYM we remap the address for the global by making
+ // a new section that we add to the sections found in the .o file.
+ // This new section has the file address set to what the
+ // addresses are in the .o file, and the load address is adjusted
+ // to match where it ended up in the final executable! We do this
+ // before we parse any dwarf info so that when it goes get parsed
+ // all section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable. We
+ // initially set the section size to be 1 byte, but will need to
+ // fix up these addresses further after all globals have been
+ // parsed to span the gaps, or we can find the global variable
+ // sizes from the DWARF info as we are parsing.
+
+#if 0
+ // First we find the non-stab entry that corresponds to the N_GSYM in the executable
+ Symbol *exe_gsym_symbol = exe_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData);
+#else
+ // The mach-o object file parser already matches up the N_GSYM with with the non-stab
+ // entry, so we shouldn't have to do that. If this ever changes, enable the code above
+ // in the "#if 0" block. STSYM's always match the symbol as found below.
+ Symbol *exe_gsym_symbol = exe_symbol;
+#endif
+ // Next we find the non-stab entry that corresponds to the N_GSYM in the .o file
+ Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData);
+ if (exe_gsym_symbol && oso_gsym_symbol)
+ {
+ // If we found the symbol, then we
+ Section* exe_gsym_section = const_cast<Section *>(exe_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ Section* oso_gsym_section = const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ if (oso_gsym_section)
+ {
+ SectionSP oso_gsym_section_sp (new Section (const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()),
+ oso_module, // Module (the .o file)
+ sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs
+ exe_symbol->GetMangled().GetName(), // Name the section the same as the symbol for which is was generated!
+ eSectionTypeDebug,
+ oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section
+ 1, // We don't know the size of the global, just do the main address for now.
+ 0, 0, 0));
+
+ oso_gsym_section_sp->SetLinkedLocation (exe_gsym_section,
+ exe_gsym_symbol->GetValue().GetFileAddress() - exe_gsym_section->GetFileAddress());
+ oso_gsym_section->GetChildren().AddSection(oso_gsym_section_sp);
+ comp_unit_info->debug_map_sections_sp->AddSection(oso_gsym_section_sp);
+ }
+ }
+ }
+ break;
+
+// case eSymbolTypeStatic:
+// {
+// // For each N_STSYM we remap the address for the global by making
+// // a new section that we add to the sections found in the .o file.
+// // This new section has the file address set to what the
+// // addresses are in the .o file, and the load address is adjusted
+// // to match where it ended up in the final executable! We do this
+// // before we parse any dwarf info so that when it goes get parsed
+// // all section/offset addresses that get registered will resolve
+// // correctly to the new addresses in the main executable. We
+// // initially set the section size to be 1 byte, but will need to
+// // fix up these addresses further after all globals have been
+// // parsed to span the gaps, or we can find the global variable
+// // sizes from the DWARF info as we are parsing.
+//
+//
+// Symbol *exe_stsym_symbol = exe_symbol;
+// // First we find the non-stab entry that corresponds to the N_STSYM in the .o file
+// Symbol *oso_stsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData);
+// if (exe_stsym_symbol && oso_stsym_symbol)
+// {
+// // If we found the symbol, then we
+// Section* exe_stsym_section = const_cast<Section *>(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+// Section* oso_stsym_section = const_cast<Section *>(oso_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+// if (oso_stsym_section)
+// {
+// // The load address of the symbol will use the section in the
+// // executable that contains the debug map that corresponds to
+// // the N_FUN symbol. We set the offset to reflect the offset
+// // into that section since we are creating a new section.
+// AddressRange stsym_load_range(exe_stsym_section, exe_stsym_symbol->GetValue().GetFileAddress() - exe_stsym_section->GetFileAddress(), 1);
+// // We need the symbol's section offset address from the .o file, but
+// // we need a non-zero size.
+// AddressRange stsym_file_range(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection(), exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), 1);
+//
+// // Now we create a section that we will add as a child of the
+// // section in which the .o symbol (the N_FUN) exists.
+//
+//// TODO: mimic what I did for N_FUN if that works...
+//// // We use the 1 byte for the size because we don't know the
+//// // size of the global symbol without seeing the DWARF.
+//// SectionSP oso_fun_section_sp (new Section ( NULL, oso_module, // Module (the .o file)
+//// sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs
+//// exe_symbol->GetMangled().GetName(),// Name the section the same as the symbol for which is was generated!
+//// // &stsym_load_range, // Load offset is the offset into the executable section for the N_FUN from the debug map
+//// &stsym_file_range, // File section/offset is just the same os the symbol on the .o file
+//// 0, 0, 0));
+////
+//// // Now we add the new section to the .o file's sections as a child
+//// // of the section in which the N_SECT symbol exists.
+//// oso_stsym_section->GetChildren().AddSection(oso_fun_section_sp);
+//// comp_unit_info->debug_map_sections_sp->AddSection(oso_fun_section_sp);
+// }
+// }
+// }
+// break;
+ }
+ }
+ }
+#if defined(DEBUG_OSO_DMAP)
+ s << "OSO sections after:\n";
+ oso_objfile->GetSectionList()->Dump(&s, NULL, true);
+#endif
+ }
+ }
+ }
+ if (comp_unit_info->oso_symbol_vendor)
+ return (SymbolFileDWARF *)comp_unit_info->oso_symbol_vendor->GetSymbolFile();
+ return NULL;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetAbilities ()
+{
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that
+ // then we return the abilities of the first N_OSO's DWARF.
+
+ const uint32_t oso_index_count = GetNumCompileUnits();
+ if (oso_index_count > 0)
+ {
+ const uint32_t dwarf_abilities = SymbolFile::CompileUnits |
+ SymbolFile::Functions |
+ SymbolFile::Blocks |
+ SymbolFile::GlobalVariables |
+ SymbolFile::LocalVariables |
+ SymbolFile::VariableTypes |
+ SymbolFile::LineTables;
+
+ for (uint32_t oso_idx=0; oso_idx<oso_index_count; ++oso_idx)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ {
+ uint32_t oso_abilities = oso_dwarf->GetAbilities();
+ if ((oso_abilities & dwarf_abilities) == dwarf_abilities)
+ return oso_abilities;
+ }
+ }
+ }
+ return 0;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetNumCompileUnits()
+{
+ InitOSO ();
+ return m_compile_unit_infos.size();
+}
+
+
+CompUnitSP
+SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx)
+{
+ CompUnitSP comp_unit_sp;
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ if (cu_idx < cu_count)
+ {
+ if (m_compile_unit_infos[cu_idx].oso_compile_unit_sp.get() == NULL)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (cu_idx);
+ if (oso_dwarf)
+ {
+ // There is only one compile unit for N_OSO entry right now, so
+ // it will always exist at index zero.
+ m_compile_unit_infos[cu_idx].oso_compile_unit_sp = m_compile_unit_infos[cu_idx].oso_symbol_vendor->GetCompileUnitAtIndex (0);
+ }
+
+ if (m_compile_unit_infos[cu_idx].oso_compile_unit_sp.get() == NULL)
+ {
+ // We weren't able to get the DWARF for this N_OSO entry (the
+ // .o file may be missing or not at the specified path), make
+ // one up as best we can from the debug map. We set the uid
+ // of the compile unit to the symbol index with the MSBit set
+ // so that it doesn't collide with any uid values from the DWARF
+ Symbol *so_symbol = m_compile_unit_infos[cu_idx].so_symbol;
+ if (so_symbol)
+ {
+ m_compile_unit_infos[cu_idx].oso_compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(),
+ NULL,
+ so_symbol->GetMangled().GetName().AsCString(),
+ cu_idx,
+ Language::Unknown));
+ }
+ }
+ }
+ comp_unit_sp = m_compile_unit_infos[cu_idx].oso_compile_unit_sp;
+ }
+
+ return comp_unit_sp;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompUnitInfo (const SymbolContext& sc)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ if (sc.comp_unit == m_compile_unit_infos[i].oso_compile_unit_sp.get())
+ return &m_compile_unit_infos[i];
+ }
+ return NULL;
+}
+
+size_t
+SymbolFileDWARFDebugMap::ParseCompileUnitFunctions (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitFunctions (sc);
+ return 0;
+}
+
+bool
+SymbolFileDWARFDebugMap::ParseCompileUnitLineTable (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitLineTable (sc);
+ return false;
+}
+
+bool
+SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitSupportFiles (sc, support_files);
+ return false;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseFunctionBlocks (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseFunctionBlocks (sc);
+ return 0;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseTypes (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseTypes (sc);
+ return 0;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseVariablesForContext (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseTypes (sc);
+ return 0;
+}
+
+
+
+Type*
+SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ return NULL;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::ResolveSymbolContext (const Address& exe_so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ uint32_t resolved_flags = 0;
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ const addr_t exe_file_addr = exe_so_addr.GetFileAddress();
+ sc.symbol = symtab->FindSymbolContainingFileAddress (exe_file_addr, &m_func_indexes[0], m_func_indexes.size());
+
+ if (sc.symbol != NULL)
+ {
+ resolved_flags |= eSymbolContextSymbol;
+
+ uint32_t oso_idx = 0;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (sc.symbol->GetID(), &oso_idx);
+ if (comp_unit_info)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ ObjectFile *oso_objfile = GetObjectFileByOSOIndex (oso_idx);
+ if (oso_dwarf && oso_objfile)
+ {
+ SectionList *oso_section_list = oso_objfile->GetSectionList();
+
+
+ SectionSP oso_section_sp(oso_section_list->FindSectionByName(exe_so_addr.GetSection()->GetName()));
+ if (oso_section_sp)
+ {
+ SectionSP oso_symbol_section_sp (oso_section_sp->GetChildren().FindSectionContainingLinkedFileAddress (exe_file_addr));
+
+ if (oso_symbol_section_sp)
+ {
+ const addr_t linked_file_addr = oso_symbol_section_sp->GetLinkedFileAddress();
+ Address oso_so_addr (oso_symbol_section_sp.get(), exe_file_addr - linked_file_addr);
+ if (oso_so_addr.IsSectionOffset())
+ resolved_flags |= oso_dwarf->ResolveSymbolContext (oso_so_addr, resolve_scope, sc);
+ }
+ }
+ // Map the load address from in the executable back to a
+ // section/offset address in the .o file so we can do
+ // lookups in the .o DWARF.
+// Address oso_so_addr (exe_load_addr, false, comp_unit_info->debug_map_sections_sp.get());
+//
+// // Make sure we were able to resolve this back to a .o
+// // section offset address, and if so, resolve the context
+// // for everything that was asked for.
+// if (oso_so_addr.IsSectionOffset())
+// resolved_flags |= oso_dwarf->ResolveSymbolContext (oso_so_addr, resolve_scope, sc);
+ }
+ }
+ }
+ }
+ return resolved_flags;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ uint32_t initial = sc_list.GetSize();
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ FileSpec so_file_spec;
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ if (GetFileSpecForSO (i, so_file_spec))
+ {
+ // By passing false to the comparison we will be able to match
+ // and files given a filename only. If both file_spec and
+ // so_file_spec have directories, we will still do a full match.
+ if (FileSpec::Compare (file_spec, so_file_spec, false) == 0)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (i);
+
+ oso_dwarf->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list);
+ }
+ }
+ }
+ return sc_list.GetSize() - initial;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::PrivateFindGlobalVariables
+(
+ const ConstString &name,
+ const std::vector<uint32_t> &indexes, // Indexes into the symbol table that match "name"
+ uint32_t max_matches,
+ VariableList& variables
+)
+{
+ const uint32_t original_size = variables.GetSize();
+ const size_t match_count = indexes.size();
+ for (size_t i=0; i<match_count; ++i)
+ {
+ uint32_t oso_idx;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (indexes[i], &oso_idx);
+ if (comp_unit_info)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ {
+ if (oso_dwarf->FindGlobalVariables(name, true, max_matches, variables))
+ if (variables.GetSize() > max_matches)
+ break;
+ }
+ }
+ }
+ return variables.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
+{
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> indexes;
+ const size_t match_count = m_obj_file->GetSymtab()->FindAllSymbolsWithNameAndType (name, eSymbolTypeGlobal, indexes);
+ if (match_count)
+ {
+ PrivateFindGlobalVariables (name, indexes, max_matches, variables);
+ }
+ }
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ return 0;
+}
+
+
+int
+SymbolFileDWARFDebugMap::SymbolContainsSymbolIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info)
+{
+ const uint32_t symbol_idx = *symbol_idx_ptr;
+
+ if (symbol_idx < comp_unit_info->so_symbol->GetID())
+ return -1;
+
+ if (symbol_idx < comp_unit_info->so_symbol->GetSiblingIndex())
+ return 0;
+
+ return 1;
+}
+
+
+SymbolFileDWARFDebugMap::CompileUnitInfo*
+SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr)
+{
+ const uint32_t oso_index_count = m_compile_unit_infos.size();
+ CompileUnitInfo *comp_unit_info = NULL;
+ if (oso_index_count)
+ {
+ comp_unit_info = (CompileUnitInfo*)bsearch(&symbol_idx, &m_compile_unit_infos[0], m_compile_unit_infos.size(), sizeof(CompileUnitInfo), (comparison_function)SymbolContainsSymbolIndex);
+ }
+
+ if (oso_idx_ptr)
+ {
+ if (comp_unit_info != NULL)
+ *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0];
+ else
+ *oso_idx_ptr = UINT32_MAX;
+ }
+ return comp_unit_info;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (name = %s)",
+ name.GetCString());
+
+
+ std::vector<uint32_t> indexes;
+ uint32_t initial_size = 0;
+ if (append)
+ initial_size = sc_list.GetSize();
+ else
+ sc_list.Clear();
+
+ const size_t match_count = m_obj_file->GetSymtab()->FindAllSymbolsWithNameAndType (name, eSymbolTypeFunction, indexes);
+ if (match_count > 0)
+ {
+ for (size_t i=0; i<match_count; ++i)
+ {
+ uint32_t oso_idx;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (indexes[i], &oso_idx);
+ if (comp_unit_info)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ oso_dwarf->FindFunctions(name, true, sc_list);
+ }
+ }
+// Stream s(stdout);
+// sc_list.Dump(&s);
+ }
+
+ return sc_list.GetSize() - initial_size;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions (const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+
+ return 0;
+}
+
+//
+//uint32_t
+//SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+// if (oso_dwarf)
+// return oso_dwarf->FindTypes (sc, name, append, max_matches, encoding, udt_uid, types);
+// return 0;
+//}
+//
+//
+//uint32_t
+//SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+// if (oso_dwarf)
+// return oso_dwarf->FindTypes (sc, regex, append, max_matches, encoding, udt_uid, types);
+// return 0;
+//}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolFileDWARFDebugMap::GetPluginName()
+{
+ return "SymbolFileDWARFDebugMap";
+}
+
+const char *
+SymbolFileDWARFDebugMap::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileDWARFDebugMap::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolFileDWARFDebugMap::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolFileDWARFDebugMap::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
new file mode 100644
index 0000000..0a312ab
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -0,0 +1,186 @@
+//===-- SymbolFileDWARFDebugMap.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_SymbolFileDWARFDebugMap_h_
+#define liblldb_SymbolFileDWARFDebugMap_h_
+
+
+#include <vector>
+#include <bitset>
+#include "lldb/Symbol/SymbolFile.h"
+
+class SymbolFileDWARF;
+
+class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile *
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileDWARFDebugMap (lldb_private::ObjectFile* ofile);
+ virtual ~ SymbolFileDWARFDebugMap ();
+
+ virtual uint32_t GetAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits ();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index);
+
+ virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
+ virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type* ResolveTypeUID (lldb::user_id_t type_uid);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindGlobalVariables (const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindGlobalVariables (const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindFunctions (const lldb_private::ConstString &name, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list);
+// virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types);
+// virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+protected:
+ enum
+ {
+ kHaveInitializedOSOs = (1 << 0),
+ kNumFlags
+ };
+
+ //------------------------------------------------------------------
+ // Class specific types
+ //------------------------------------------------------------------
+ struct CompileUnitInfo
+ {
+ lldb_private::FileSpec so_file;
+ lldb_private::Symbol *so_symbol;
+ lldb_private::Symbol *oso_symbol;
+ lldb::ModuleSP oso_module_sp;
+ lldb::CompUnitSP oso_compile_unit_sp;
+ lldb_private::SymbolVendor *oso_symbol_vendor;
+// lldb_private::shared_ptr<SymbolFileDWARF> oso_dwarf_sp;
+// lldb_private::shared_ptr<SymbolVendor> oso_dwarf_sp;
+ std::vector<uint32_t> function_indexes;
+ std::vector<uint32_t> static_indexes;
+ lldb::SharedPtr<lldb_private::SectionList>::Type debug_map_sections_sp;
+
+ CompileUnitInfo() :
+ so_file(),
+ so_symbol(NULL),
+ oso_symbol(NULL),
+ oso_module_sp(),
+ oso_compile_unit_sp(),
+ oso_symbol_vendor(NULL),
+// oso_dwarf_sp(),
+ function_indexes(),
+ static_indexes(),
+ debug_map_sections_sp()
+ {
+ }
+ };
+
+ //------------------------------------------------------------------
+ // Protected Member Functions
+ //------------------------------------------------------------------
+ void
+ InitOSO ();
+
+ bool
+ GetFileSpecForSO (uint32_t oso_idx, lldb_private::FileSpec &file_spec);
+
+ CompileUnitInfo *
+ GetCompUnitInfo (const lldb_private::SymbolContext& sc);
+
+ lldb_private::Module *
+ GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ lldb_private::Module *
+ GetModuleByOSOIndex (uint32_t oso_idx);
+
+ lldb_private::ObjectFile *
+ GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ lldb_private::ObjectFile *
+ GetObjectFileByOSOIndex (uint32_t oso_idx);
+
+ SymbolFileDWARF *
+ GetSymbolFile (const lldb_private::SymbolContext& sc);
+
+ SymbolFileDWARF *
+ GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ SymbolFileDWARF *
+ GetSymbolFileByOSOIndex (uint32_t oso_idx);
+
+ CompileUnitInfo*
+ GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr);
+
+ static int
+ SymbolContainsSymbolIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info);
+
+ uint32_t
+ PrivateFindGlobalVariables (const lldb_private::ConstString &name,
+ const std::vector<uint32_t> &name_symbol_indexes,
+ uint32_t max_matches,
+ lldb_private::VariableList& variables);
+
+ //------------------------------------------------------------------
+ // Member Variables
+ //------------------------------------------------------------------
+ std::bitset<kNumFlags> m_flags;
+ std::vector<CompileUnitInfo> m_compile_unit_infos;
+ std::vector<uint32_t> m_func_indexes; // Sorted by address
+ std::vector<uint32_t> m_glob_indexes;
+};
+
+#endif // #ifndef liblldb_SymbolFileDWARFDebugMap_h_
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
new file mode 100644
index 0000000..d7da356
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -0,0 +1,401 @@
+//===-- SymbolFileSymtab.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileSymtab.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Function.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SymbolFileSymtab::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileSymtab::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+SymbolFileSymtab::GetPluginNameStatic()
+{
+ return "symbol-file.symtab";
+}
+
+const char *
+SymbolFileSymtab::GetPluginDescriptionStatic()
+{
+ return "Reads debug symbols from an object file's symbol table.";
+}
+
+
+SymbolFile*
+SymbolFileSymtab::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileSymtab(obj_file);
+}
+
+SymbolFileSymtab::SymbolFileSymtab(ObjectFile* obj_file) :
+ SymbolFile(obj_file),
+ m_source_indexes(),
+ m_func_indexes(),
+ m_code_indexes(),
+ m_data_indexes(),
+ m_addr_indexes()
+{
+}
+
+SymbolFileSymtab::~SymbolFileSymtab()
+{
+}
+
+
+uint32_t
+SymbolFileSymtab::GetAbilities ()
+{
+ uint32_t abilities = 0;
+ const Symtab *symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+
+ //----------------------------------------------------------------------
+ // The snippet of code below will get the indexes the module symbol
+ // table entries that are code, data, or function related (debug info),
+ // sort them by value (address) and dump the sorted symbols.
+ //----------------------------------------------------------------------
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile, m_source_indexes);
+ if (!m_source_indexes.empty())
+ {
+ abilities |= CompileUnits;
+ }
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeFunction, m_func_indexes);
+ if (!m_func_indexes.empty())
+ {
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ abilities |= Functions;
+ }
+
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, m_code_indexes);
+ if (!m_code_indexes.empty())
+ {
+ symtab->SortSymbolIndexesByValue(m_code_indexes, true);
+ abilities |= Labels;
+ }
+
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeData, m_data_indexes);
+
+ if (!m_data_indexes.empty())
+ {
+ symtab->SortSymbolIndexesByValue(m_data_indexes, true);
+ abilities |= GlobalVariables;
+ }
+ }
+
+ return abilities;
+}
+
+uint32_t
+SymbolFileSymtab::GetNumCompileUnits()
+{
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (m_source_indexes.empty())
+ return 1;
+
+ // If we have any source file symbols we will logically orgnize the object symbols
+ // using these.
+ return m_source_indexes.size();
+}
+
+CompUnitSP
+SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx)
+{
+ CompUnitSP cu_sp;
+
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (m_source_indexes.empty())
+ {
+ const FileSpec &obj_file_spec = m_obj_file->GetFileSpec();
+ if (obj_file_spec)
+ cu_sp.reset(new CompileUnit(m_obj_file->GetModule(), NULL, obj_file_spec, 0, Language::Unknown));
+
+ }
+ else if (idx < m_source_indexes.size())
+ {
+ const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]);
+ if (cu_symbol)
+ cu_sp.reset(new CompileUnit(m_obj_file->GetModule(), NULL, cu_symbol->GetMangled().GetName().AsCString(), 0, Language::Unknown));
+ }
+ return cu_sp;
+}
+
+size_t
+SymbolFileSymtab::ParseCompileUnitFunctions (const SymbolContext &sc)
+{
+ size_t num_added = 0;
+ // We must at least have a valid compile unit
+ assert (sc.comp_unit != NULL);
+ const Symtab *symtab = m_obj_file->GetSymtab();
+ const Symbol *curr_symbol = NULL;
+ const Symbol *next_symbol = NULL;
+// const char *prefix = m_obj_file->SymbolPrefix();
+// if (prefix == NULL)
+// prefix == "";
+//
+// const uint32_t prefix_len = strlen(prefix);
+
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (m_source_indexes.empty())
+ {
+ // The only time we will have a user ID of zero is when we don't have
+ // and source file symbols and we declare one compile unit for the
+ // entire object file
+ if (!m_func_indexes.empty())
+ {
+
+ }
+
+ if (!m_code_indexes.empty())
+ {
+// StreamFile s(stdout);
+// symtab->Dump(&s, m_code_indexes);
+
+ uint32_t idx = 0; // Index into the indexes
+ const uint32_t num_indexes = m_code_indexes.size();
+ for (idx = 0; idx < num_indexes; ++idx)
+ {
+ uint32_t symbol_idx = m_code_indexes[idx];
+ curr_symbol = symtab->SymbolAtIndex(symbol_idx);
+ if (curr_symbol)
+ {
+ // Union of all ranges in the function DIE (if the function is discontiguous)
+ AddressRange func_range(curr_symbol->GetValue(), 0);
+ if (func_range.GetBaseAddress().IsSectionOffset())
+ {
+ uint32_t symbol_size = curr_symbol->GetByteSize();
+ if (symbol_size != 0 && !curr_symbol->GetSizeIsSibling())
+ func_range.SetByteSize(symbol_size);
+ else if (idx + 1 < num_indexes)
+ {
+ next_symbol = symtab->SymbolAtIndex(m_code_indexes[idx + 1]);
+ if (next_symbol)
+ {
+ func_range.SetByteSize(next_symbol->GetValue().GetOffset() - curr_symbol->GetValue().GetOffset());
+ }
+ }
+
+ FunctionSP func_sp(new Function(sc.comp_unit,
+ symbol_idx, // UserID is the DIE offset
+ LLDB_INVALID_UID, // We don't have any type info for this function
+ curr_symbol->GetMangled(), // Linker/mangled name
+ NULL, // no return type for a code symbol...
+ func_range)); // first address range
+
+ if (func_sp.get() != NULL)
+ {
+ sc.comp_unit->AddFunction(func_sp);
+ ++num_added;
+ }
+ }
+ }
+ }
+
+ }
+ }
+ else
+ {
+ // We assume we
+ }
+ return num_added;
+}
+
+bool
+SymbolFileSymtab::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ return false;
+}
+
+bool
+SymbolFileSymtab::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files)
+{
+ return false;
+}
+
+size_t
+SymbolFileSymtab::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ return 0;
+}
+
+
+size_t
+SymbolFileSymtab::ParseTypes (const SymbolContext &sc)
+{
+ return 0;
+}
+
+
+size_t
+SymbolFileSymtab::ParseVariablesForContext (const SymbolContext& sc)
+{
+ return 0;
+}
+
+Type*
+SymbolFileSymtab::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ return NULL;
+}
+
+
+
+uint32_t
+SymbolFileSymtab::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ if (m_obj_file->GetSymtab() == NULL)
+ return 0;
+
+ uint32_t resolved_flags = 0;
+ if (resolve_scope & eSymbolContextSymbol)
+ {
+ sc.symbol = m_obj_file->GetSymtab()->FindSymbolContainingFileAddress(so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+ return resolved_flags;
+}
+
+uint32_t
+SymbolFileSymtab::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindGlobalVariables(const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (name = '%s')",
+ name.GetCString());
+
+ Symtab *symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ const uint32_t start_size = sc_list.GetSize();
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeFunction, symbol_indexes);
+ symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeCode, symbol_indexes);
+ const uint32_t num_matches = symbol_indexes.size();
+ if (num_matches)
+ {
+ SymbolContext sc(m_obj_file->GetModule());
+ for (uint32_t i=0; i<num_matches; i++)
+ {
+ sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
+ sc_list.Append(sc);
+ }
+ }
+ return sc_list.GetSize() - start_size;
+ }
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ return 0;
+}
+
+//uint32_t
+//SymbolFileSymtab::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// return 0;
+//}
+//
+//uint32_t
+//SymbolFileSymtab::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// return 0;
+//}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolFileSymtab::GetPluginName()
+{
+ return "SymbolFileSymtab";
+}
+
+const char *
+SymbolFileSymtab::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileSymtab::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileSymtab::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolFileSymtab::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolFileSymtab::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
new file mode 100644
index 0000000..ac73f29
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -0,0 +1,136 @@
+//===-- SymbolFileSymtab.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_SymbolFileSymtab_h_
+#define liblldb_SymbolFileSymtab_h_
+
+#include "lldb/Symbol/SymbolFile.h"
+#include <vector>
+
+class SymbolFileSymtab : public lldb_private::SymbolFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile*
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileSymtab(lldb_private::ObjectFile* obj_file);
+
+ virtual
+ ~SymbolFileSymtab();
+
+ virtual uint32_t GetAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetNumCompileUnits();
+
+ virtual lldb::CompUnitSP
+ ParseCompileUnitAtIndex(uint32_t index);
+
+ virtual size_t
+ ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
+
+ virtual size_t
+ ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseTypes (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type*
+ ResolveTypeUID(lldb::user_id_t type_uid);
+
+ virtual uint32_t
+ ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+
+ virtual uint32_t
+ ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindGlobalVariables(const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+
+ virtual uint32_t
+ FindGlobalVariables(const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+
+ virtual uint32_t
+ FindFunctions(const lldb_private::ConstString &name, bool append, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindFunctions(const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list);
+
+// virtual uint32_t
+// FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+
+// virtual uint32_t
+// FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+
+protected:
+ std::vector<uint32_t> m_source_indexes;
+ std::vector<uint32_t> m_func_indexes;
+ std::vector<uint32_t> m_code_indexes;
+ std::vector<uint32_t> m_data_indexes;
+ std::vector<uint32_t> m_addr_indexes; // Anything that needs to go into an search by address
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileSymtab);
+};
+
+
+#endif // liblldb_SymbolFileSymtab_h_
diff --git a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
new file mode 100644
index 0000000..270d7ed
--- /dev/null
+++ b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
@@ -0,0 +1,339 @@
+//===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolVendorMacOSX.h"
+
+#include <mach/machine.h> // DebugSymbols needs this on Leopard...
+
+#include <AvailabilityMacros.h>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SymbolVendorMacOSX constructor
+//----------------------------------------------------------------------
+SymbolVendorMacOSX::SymbolVendorMacOSX(Module *module) :
+ SymbolVendor(module)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SymbolVendorMacOSX::~SymbolVendorMacOSX()
+{
+}
+
+
+static bool
+UUIDsMatch(Module *module, ObjectFile *ofile)
+{
+ if (module && ofile)
+ {
+ // Make sure the UUIDs match
+ UUID dsym_uuid;
+ if (ofile->GetUUID(&dsym_uuid))
+ return dsym_uuid == module->GetUUID();
+ }
+ return false;
+}
+
+
+//ObjectFile *
+//LocateDSYMMachFileInDSYMBundle (Module* module, FileSpec& dsym_fspec)
+//{
+// ObjectFile *dsym_objfile = NULL;
+//
+// char path[PATH_MAX];
+//
+// if (dsym_fspec.GetPath(path, sizeof(path)))
+// {
+// size_t path_len = strlen(path);
+// const char *bundle_subpath = "/Contents/Resources/DWARF/";
+// if (path_len > 0)
+// {
+// if (path[path_len-1] == '/')
+// ::strncat (path, bundle_subpath + 1, sizeof(path));
+// else
+// ::strncat (path, bundle_subpath, sizeof(path));
+// ::strncat (path, dsym_fspec.GetFilename().AsCString(), sizeof(path));
+//
+// path_len = strlen(path);
+//
+// if (::strcasecmp (&path[path_len - strlen(".dSYM")], ".dSYM") == 0)
+// {
+// path[path_len - ::strlen(".dSYM")] = '\0';
+// dsym_fspec.SetFile(path);
+// dsym_objfile = ObjectFile::FindPlugin(module, &dsym_fspec, 0);
+// }
+// }
+// }
+// return dsym_objfile;
+//}
+//
+//CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url) __attribute__((weak_import));
+
+
+//ObjectFile *
+//FindDSYMUsingDebugSymbols (Module* module, FileSpec& dsym_fspec)
+//{
+// Timer scoped_locate("FindDSYMUsingDebugSymbols");
+// dsym_fspec.Clear();
+// ObjectFile *dsym_objfile = NULL;
+// if (module->GetUUID().IsValid())
+// {
+// // Try and locate the dSYM file using DebugSymbols first
+// const UInt8 *module_uuid = (const UInt8 *)module->GetUUID().GetBytes();
+// if (module_uuid != NULL)
+// {
+// CFUUIDRef module_uuid_ref;
+// module_uuid_ref = ::CFUUIDCreateWithBytes ( NULL,
+// module_uuid[0],
+// module_uuid[1],
+// module_uuid[2],
+// module_uuid[3],
+// module_uuid[4],
+// module_uuid[5],
+// module_uuid[6],
+// module_uuid[7],
+// module_uuid[8],
+// module_uuid[9],
+// module_uuid[10],
+// module_uuid[11],
+// module_uuid[12],
+// module_uuid[13],
+// module_uuid[14],
+// module_uuid[15]);
+//
+// if (module_uuid_ref)
+// {
+// CFURLRef dsym_url = NULL;
+// CFURLRef exec_url = NULL;
+//
+// // if (DBGCopyFullDSYMURLForUUID)
+// {
+// char exec_path[PATH_MAX];
+// if (module->GetFileSpec().GetPath(exec_path, sizeof(exec_path)))
+// {
+// exec_url = CFURLCreateFromFileSystemRepresentation ( NULL,
+// (const UInt8 *)exec_path,
+// strlen(exec_path),
+// FALSE);
+// }
+//
+// dsym_url = DBGCopyFullDSYMURLForUUID(module_uuid_ref, exec_url);
+// }
+// // else
+// // {
+// // dsym_url = DBGCopyDSYMURLForUUID(module_uuid_ref);
+// // }
+//
+// if (exec_url)
+// {
+// ::CFRelease (exec_url);
+// exec_url = NULL;
+// }
+//
+// ::CFRelease(module_uuid_ref);
+// module_uuid_ref = NULL;
+//
+// if (dsym_url)
+// {
+// char dsym_path[PATH_MAX];
+// Boolean success = CFURLGetFileSystemRepresentation (dsym_url, true, (UInt8*)dsym_path, sizeof(dsym_path)-1);
+//
+// ::CFRelease(dsym_url), dsym_url = NULL;
+//
+// if (success)
+// {
+// dsym_fspec.SetFile(dsym_path);
+//
+// // Some newer versions of DebugSymbols will return a full path into a dSYM bundle
+// // that points to the correct mach file within the dSYM bundle (MH_DSYM mach file
+// // type).
+// dsym_objfile = ObjectFile::FindPlugin(module, &dsym_fspec, 0);
+//
+// // Olders versions of DebugSymbols will return a path to a dSYM bundle.
+// if (dsym_objfile == NULL)
+// dsym_objfile = LocateDSYMMachFileInDSYMBundle (module, dsym_fspec);
+// }
+// }
+// }
+// }
+// }
+// return dsym_objfile;
+//}
+
+static void
+ReplaceDSYMSectionsWithExecutableSections (ObjectFile *exec_objfile, ObjectFile *dsym_objfile)
+{
+ // We need both the executable and the dSYM to live off of the
+ // same section lists. So we take all of the sections from the
+ // executable, and replace them in the dSYM. This allows section
+ // offset addresses that come from the dSYM to automatically
+ // get updated as images (shared libraries) get loaded and
+ // unloaded.
+ SectionList *exec_section_list = exec_objfile->GetSectionList();
+ SectionList *dsym_section_list = dsym_objfile->GetSectionList();
+ if (exec_section_list && dsym_section_list)
+ {
+ const uint32_t num_exec_sections = dsym_section_list->GetSize();
+ uint32_t exec_sect_idx;
+ for (exec_sect_idx = 0; exec_sect_idx < num_exec_sections; ++exec_sect_idx)
+ {
+ SectionSP exec_sect_sp(exec_section_list->GetSectionAtIndex(exec_sect_idx));
+ if (exec_sect_sp.get())
+ {
+ // Try and replace any sections that exist in both the executable
+ // and in the dSYM with those from the executable. If we fail to
+ // replace the one in the dSYM, then add the executable section to
+ // the dSYM.
+ if (dsym_section_list->ReplaceSection(exec_sect_sp->GetID(), exec_sect_sp, 0) == false)
+ dsym_section_list->AddSection(exec_sect_sp);
+ }
+ }
+ }
+}
+
+void
+SymbolVendorMacOSX::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolVendorMacOSX::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+SymbolVendorMacOSX::GetPluginNameStatic()
+{
+ return "symbol-vendor.macosx";
+}
+
+const char *
+SymbolVendorMacOSX::GetPluginDescriptionStatic()
+{
+ return "Symbol vendor for MacOSX that looks for dSYM files that match executables.";
+}
+
+
+
+//----------------------------------------------------------------------
+// CreateInstance
+//
+// Platforms can register a callback to use when creating symbol
+// vendors to allow for complex debug information file setups, and to
+// also allow for finding separate debug information files.
+//----------------------------------------------------------------------
+SymbolVendor*
+SymbolVendorMacOSX::CreateInstance(Module* module)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolVendorMacOSX::CreateInstance (module = %s/%s)",
+ module->GetFileSpec().GetDirectory().AsCString(),
+ module->GetFileSpec().GetFilename().AsCString());
+ SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module);
+ if (symbol_vendor)
+ {
+ char path[PATH_MAX];
+ path[0] = '\0';
+
+ // Try and locate the dSYM file on Mac OS X
+ ObjectFile * obj_file = module->GetObjectFile();
+ if (obj_file)
+ {
+ Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM",
+ "SymbolVendorMacOSX::CreateInstance (module = %s/%s) locate dSYM",
+ module->GetFileSpec().GetDirectory().AsCString(),
+ module->GetFileSpec().GetFilename().AsCString());
+
+ FileSpec dsym_fspec;
+ std::auto_ptr<ObjectFile> dsym_objfile_ap;
+ const FileSpec &file_spec = obj_file->GetFileSpec();
+ if (file_spec)
+ {
+ dsym_fspec = Symbols::LocateExecutableSymbolFile (&file_spec, &module->GetArchitecture(), &module->GetUUID());
+
+ if (dsym_fspec)
+ {
+ dsym_objfile_ap.reset(ObjectFile::FindPlugin(module, &dsym_fspec, 0, dsym_fspec.GetByteSize()));
+ if (UUIDsMatch(module, dsym_objfile_ap.get()))
+ {
+ ReplaceDSYMSectionsWithExecutableSections (obj_file, dsym_objfile_ap.get());
+ symbol_vendor->AddSymbolFileRepresendation(dsym_objfile_ap.release());
+ return symbol_vendor;
+ }
+ }
+ }
+
+ // Just create our symbol vendor using the current objfile as this is either
+ // an executable with no dSYM (that we could locate), and executable with
+ // a dSYM that has a UUID that doesn't match, or it is a dSYM file itself.
+ symbol_vendor->AddSymbolFileRepresendation(obj_file);
+ }
+ }
+ return symbol_vendor;
+}
+
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolVendorMacOSX::GetPluginName()
+{
+ return "SymbolVendorMacOSX";
+}
+
+const char *
+SymbolVendorMacOSX::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolVendorMacOSX::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolVendorMacOSX::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolVendorMacOSX::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolVendorMacOSX::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h
new file mode 100644
index 0000000..adbf648
--- /dev/null
+++ b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h
@@ -0,0 +1,71 @@
+//===-- SymbolVendorMacOSX.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_SymbolVendorMacOSX_h_
+#define liblldb_SymbolVendorMacOSX_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+class SymbolVendorMacOSX : public lldb_private::SymbolVendor
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolVendor*
+ CreateInstance (lldb_private::Module *module);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolVendorMacOSX (lldb_private::Module *module);
+
+ virtual
+ ~SymbolVendorMacOSX();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolVendorMacOSX);
+};
+
+#endif // liblldb_SymbolVendorMacOSX_h_