aboutsummaryrefslogtreecommitdiffstats
path: root/source/Plugins/Process
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committerEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitf034231a6a1fd5d6395206c1651de8cd9402cca3 (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec /source/Plugins/Process
downloadsrc-f034231a6a1fd5d6395206c1651de8cd9402cca3.tar.gz
src-f034231a6a1fd5d6395206c1651de8cd9402cca3.zip
Import lldb as of SVN r188801
(A number of files not required for the FreeBSD build have been removed.) Sponsored by: DARPA, AFRL
Notes
Notes: svn path=/vendor/lldb/dist/; revision=254721
Diffstat (limited to 'source/Plugins/Process')
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp132
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.h82
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.cpp1677
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.h322
-rw-r--r--source/Plugins/Process/POSIX/POSIXStopInfo.cpp89
-rw-r--r--source/Plugins/Process/POSIX/POSIXStopInfo.h120
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.cpp578
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.h133
-rw-r--r--source/Plugins/Process/POSIX/ProcessMessage.cpp258
-rw-r--r--source/Plugins/Process/POSIX/ProcessMessage.h207
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.cpp911
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.h211
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp193
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.h111
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp136
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h32
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp180
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h32
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIX.h70
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_i386.cpp551
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_i386.h169
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86.h110
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp1563
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86_64.h347
-rw-r--r--source/Plugins/Process/Utility/ARMDefines.h110
-rw-r--r--source/Plugins/Process/Utility/ARMUtils.h394
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp279
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.h85
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.cpp274
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.h43
-rw-r--r--source/Plugins/Process/Utility/InstructionUtils.h136
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp1226
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.h333
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp980
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.h269
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp1066
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h274
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.cpp137
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp1541
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.h212
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp206
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.cpp87
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.h56
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.cpp174
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.h102
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp261
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.h114
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.cpp482
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.h77
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.cpp140
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.h152
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.cpp322
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.h125
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp275
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h74
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.cpp619
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.h171
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp68
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h47
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp68
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h54
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.cpp176
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.h174
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp643
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h268
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp2348
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h430
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp839
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h147
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp971
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h311
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp3291
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h396
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp196
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h57
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp214
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.h107
83 files changed, 30211 insertions, 0 deletions
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
new file mode 100644
index 000000000000..ea26d972b860
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -0,0 +1,132 @@
+//===-- ProcessFreeBSD.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>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "ProcessMonitor.h"
+#include "POSIXThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static functions.
+
+lldb::ProcessSP
+ProcessFreeBSD::CreateInstance(Target& target,
+ Listener &listener,
+ const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset(new ProcessFreeBSD (target, listener));
+ return process_sp;
+}
+
+void
+ProcessFreeBSD::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (!g_initialized)
+ {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ Log::Callbacks log_callbacks = {
+ ProcessPOSIXLog::DisableLog,
+ ProcessPOSIXLog::EnableLog,
+ ProcessPOSIXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessFreeBSD::GetPluginNameStatic(), log_callbacks);
+ ProcessPOSIXLog::RegisterPluginName(GetPluginNameStatic());
+ g_initialized = true;
+ }
+}
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginNameStatic()
+{
+ static ConstString g_name("freebsd");
+ return g_name;
+}
+
+const char *
+ProcessFreeBSD::GetPluginDescriptionStatic()
+{
+ return "Process plugin for FreeBSD";
+}
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessFreeBSD::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessFreeBSD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+Error
+ProcessFreeBSD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Log *
+ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener)
+ : ProcessPOSIX(target, listener)
+{
+}
+
+void
+ProcessFreeBSD::Terminate()
+{
+}
+
+bool
+ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // XXX haxx
+ new_thread_list = old_thread_list;
+
+ return false;
+}
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
new file mode 100644
index 000000000000..5f79b74cad30
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -0,0 +1,82 @@
+//===-- ProcessFreeBSD.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_ProcessFreeBSD_H_
+#define liblldb_ProcessFreeBSD_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ThreadList.h"
+#include "ProcessMessage.h"
+#include "ProcessPOSIX.h"
+
+class ProcessMonitor;
+
+class ProcessFreeBSD :
+ public ProcessPOSIX
+{
+
+public:
+ //------------------------------------------------------------------
+ // Static functions.
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessFreeBSD(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ 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);
+
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
new file mode 100644
index 000000000000..9fd51d2d640a
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -0,0 +1,1677 @@
+//===-- ProcessMonitor.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 <poll.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+
+#include "POSIXThread.h"
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+
+extern "C" {
+ extern char ** environ;
+ }
+
+using namespace lldb;
+using namespace lldb_private;
+
+// We disable the tracing of ptrace calls for integration builds to
+// avoid the additional indirection and checks.
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+// Wrapper for ptrace to catch errors and log calls.
+
+const char *
+Get_PT_IO_OP(int op)
+{
+ switch (op) {
+ case PIOD_READ_D: return "READ_D";
+ case PIOD_WRITE_D: return "WRITE_D";
+ case PIOD_READ_I: return "READ_I";
+ case PIOD_WRITE_I: return "WRITE_I";
+ default: return "Unknown op";
+ }
+}
+
+// Wrapper for ptrace to catch errors and log calls.
+// Note that ptrace sets errno on error because -1 is reserved as a valid result.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
+ const char* reqName, const char* file, int line)
+{
+ long int result;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ if (log) {
+ log->Printf("ptrace(%s, %lu, %p, %x) called from file %s line %d",
+ reqName, pid, addr, data, file, line);
+ if (req == PT_IO) {
+ struct ptrace_io_desc *pi = (struct ptrace_io_desc *) addr;
+
+ log->Printf("PT_IO: op=%s offs=%zx size=%ld",
+ Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len);
+ }
+ }
+
+ //PtraceDisplayBytes(req, data);
+
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t) addr, data);
+
+ //PtraceDisplayBytes(req, data);
+
+ if (log && errno != 0)
+ {
+ const char* str;
+ switch (errno)
+ {
+ case ESRCH: str = "ESRCH"; break;
+ case EINVAL: str = "EINVAL"; break;
+ case EBUSY: str = "EBUSY"; break;
+ case EPERM: str = "EPERM"; break;
+ default: str = "<unknown>";
+ }
+ log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
+ }
+
+#ifdef __amd64__
+ if (log) {
+ if (req == PT_GETREGS) {
+ struct reg *r = (struct reg *) addr;
+
+ log->Printf("PT_GETREGS: ip=0x%lx", r->r_rip);
+ log->Printf("PT_GETREGS: sp=0x%lx", r->r_rsp);
+ log->Printf("PT_GETREGS: bp=0x%lx", r->r_rbp);
+ log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax);
+ }
+ }
+#endif
+
+ return result;
+}
+
+// Wrapper for ptrace when logging is not required.
+// Sets errno to 0 prior to calling ptrace.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data)
+{
+ long result = 0;
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t)addr, data);
+ return result;
+}
+
+#define PTRACE(req, pid, addr, data) \
+ PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
+#else
+ PtraceWrapper((req), (pid), (addr), (data))
+#endif
+
+//------------------------------------------------------------------------------
+// Static implementations of ProcessMonitor::ReadMemory and
+// ProcessMonitor::WriteMemory. This enables mutual recursion between these
+// functions without needed to go thru the thread funnel.
+
+static size_t
+DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_READ_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+static size_t
+DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, const void *buf,
+ size_t size, Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_WRITE_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = (void *)buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static bool
+EnsureFDFlags(int fd, int flags, Error &error)
+{
+ int status;
+
+ if ((status = fcntl(fd, F_GETFL)) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+/// @class Operation
+/// @brief Represents a ProcessMonitor operation.
+///
+/// Under FreeBSD, it is not possible to ptrace() from any other thread but the
+/// one that spawned or attached to the process from the start. Therefore, when
+/// a ProcessMonitor is asked to deliver or change the state of an inferior
+/// process the operation must be "funneled" to a specific thread to perform the
+/// task. The Operation class provides an abstract base for all services the
+/// ProcessMonitor must perform via the single virtual function Execute, thus
+/// encapsulating the code that needs to run in the privileged context.
+class Operation
+{
+public:
+ virtual ~Operation() {}
+ virtual void Execute(ProcessMonitor *monitor) = 0;
+};
+
+//------------------------------------------------------------------------------
+/// @class ReadOperation
+/// @brief Implements ProcessMonitor::ReadMemory.
+class ReadOperation : public Operation
+{
+public:
+ ReadOperation(lldb::addr_t addr, void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+ReadOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteOperation
+/// @brief Implements ProcessMonitor::WriteMemory.
+class WriteOperation : public Operation
+{
+public:
+ WriteOperation(lldb::addr_t addr, const void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ const void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+WriteOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadRegOperation
+/// @brief Implements ProcessMonitor::ReadRegisterValue.
+class ReadRegOperation : public Operation
+{
+public:
+ ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size,
+ RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset), m_size(size),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ unsigned m_size;
+ RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+ReadRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+ int rc;
+
+ if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0)) < 0) {
+ m_result = false;
+ } else {
+ if (m_size == sizeof(uintptr_t))
+ m_value = *(uintptr_t *)(((caddr_t)&regs) + m_offset);
+ else
+ memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteRegOperation
+/// @brief Implements ProcessMonitor::WriteRegisterValue.
+class WriteRegOperation : public Operation
+{
+public:
+ WriteRegOperation(lldb::tid_t tid, unsigned offset,
+ const RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ const RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+WriteRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+
+ if (PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0) < 0) {
+ m_result = false;
+ return;
+ }
+ *(uintptr_t *)(((caddr_t)&regs) + m_offset) = (uintptr_t)m_value.GetAsUInt64();
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)&regs, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadGPROperation
+/// @brief Implements ProcessMonitor::ReadGPR.
+class ReadGPROperation : public Operation
+{
+public:
+ ReadGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadGPROperation::Execute(ProcessMonitor *monitor)
+{
+ int rc;
+
+ errno = 0;
+ rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0);
+ if (errno != 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadFPROperation
+/// @brief Implements ProcessMonitor::ReadFPR.
+class ReadFPROperation : public Operation
+{
+public:
+ ReadFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteGPROperation
+/// @brief Implements ProcessMonitor::WriteGPR.
+class WriteGPROperation : public Operation
+{
+public:
+ WriteGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteGPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteFPROperation
+/// @brief Implements ProcessMonitor::WriteFPR.
+class WriteFPROperation : public Operation
+{
+public:
+ WriteFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ResumeOperation
+/// @brief Implements ProcessMonitor::Resume.
+class ResumeOperation : public Operation
+{
+public:
+ ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) :
+ m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+ResumeOperation::Execute(ProcessMonitor *monitor)
+{
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_CONTINUE, m_tid, (caddr_t)1, data))
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno));
+ m_result = false;
+ }
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class SingleStepOperation
+/// @brief Implements ProcessMonitor::SingleStep.
+class SingleStepOperation : public Operation
+{
+public:
+ SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result)
+ : m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+SingleStepOperation::Execute(ProcessMonitor *monitor)
+{
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_STEP, m_tid, NULL, data))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class LwpInfoOperation
+/// @brief Implements ProcessMonitor::GetLwpInfo.
+class LwpInfoOperation : public Operation
+{
+public:
+ LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err)
+ : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_info;
+ bool &m_result;
+ int &m_err;
+};
+
+void
+LwpInfoOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) {
+ m_result = false;
+ m_err = errno;
+ } else {
+ memcpy(m_info, &plwp, sizeof(plwp));
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class EventMessageOperation
+/// @brief Implements ProcessMonitor::GetEventMessage.
+class EventMessageOperation : public Operation
+{
+public:
+ EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result)
+ : m_tid(tid), m_message(message), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned long *m_message;
+ bool &m_result;
+};
+
+void
+EventMessageOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp)))
+ m_result = false;
+ else {
+ if (plwp.pl_flags & PL_FLAG_FORKED) {
+ m_message = (unsigned long *)plwp.pl_child_pid;
+ m_result = true;
+ } else
+ m_result = false;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class KillOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class KillOperation : public Operation
+{
+public:
+ KillOperation(bool &result) : m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ bool &m_result;
+};
+
+void
+KillOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_KILL, pid, NULL, 0))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class DetachOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class DetachOperation : public Operation
+{
+public:
+ DetachOperation(Error &result) : m_error(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ Error &m_error;
+};
+
+void
+DetachOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_DETACH, pid, NULL, 0) < 0)
+ m_error.SetErrorToErrno();
+
+}
+
+ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
+ : m_monitor(monitor)
+{
+ sem_init(&m_semaphore, 0, 0);
+}
+
+ProcessMonitor::OperationArgs::~OperationArgs()
+{
+ sem_destroy(&m_semaphore);
+}
+
+ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir)
+ : OperationArgs(monitor),
+ m_module(module),
+ m_argv(argv),
+ m_envp(envp),
+ m_stdin_path(stdin_path),
+ m_stdout_path(stdout_path),
+ m_stderr_path(stderr_path),
+ m_working_dir(working_dir) { }
+
+ProcessMonitor::LaunchArgs::~LaunchArgs()
+{ }
+
+ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid)
+ : OperationArgs(monitor), m_pid(pid) { }
+
+ProcessMonitor::AttachArgs::~AttachArgs()
+{ }
+
+//------------------------------------------------------------------------------
+/// The basic design of the ProcessMonitor is built around two threads.
+///
+/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
+/// for changes in the debugee state. When a change is detected a
+/// ProcessMessage is sent to the associated ProcessFreeBSD instance. This thread
+/// "drives" state changes in the debugger.
+///
+/// The second thread (@see OperationThread) is responsible for two things 1)
+/// launching or attaching to the inferior process, and then 2) servicing
+/// operations such as register reads/writes, stepping, etc. See the comments
+/// on the Operation class for more info as to why this is needed.
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
+ Module *module,
+ const char *argv[],
+ const char *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ lldb_private::Error &error)
+ : m_process(static_cast<ProcessFreeBSD *>(process)),
+ m_operation_thread(LLDB_INVALID_HOST_THREAD),
+ m_monitor_thread(LLDB_INVALID_HOST_THREAD),
+ m_pid(LLDB_INVALID_PROCESS_ID),
+ m_server_mutex(Mutex::eMutexTypeRecursive),
+ m_terminal_fd(-1),
+ m_client_fd(-1),
+ m_server_fd(-1)
+{
+ std::unique_ptr<LaunchArgs> args;
+
+ args.reset(new LaunchArgs(this, module, argv, envp,
+ stdin_path, stdout_path, stderr_path, working_dir));
+
+
+ // Server/client descriptors.
+ if (!EnableIPC())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Monitor failed to initialize.");
+ }
+
+ StartLaunchOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the launch was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess(
+ ProcessMonitor::MonitorCallback, this, GetPID(), true);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process launch failed.");
+ return;
+ }
+}
+
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
+ lldb::pid_t pid,
+ lldb_private::Error &error)
+ : m_process(static_cast<ProcessFreeBSD *>(process)),
+ m_operation_thread(LLDB_INVALID_HOST_THREAD),
+ m_monitor_thread(LLDB_INVALID_HOST_THREAD),
+ m_pid(pid),
+ m_server_mutex(Mutex::eMutexTypeRecursive),
+ m_terminal_fd(-1),
+ m_client_fd(-1),
+ m_server_fd(-1)
+{
+ std::unique_ptr<AttachArgs> args;
+
+ args.reset(new AttachArgs(this, pid));
+
+ // Server/client descriptors.
+ if (!EnableIPC())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Monitor failed to initialize.");
+ }
+
+ StartAttachOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the attach was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess(
+ ProcessMonitor::MonitorCallback, this, GetPID(), true);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process attach failed.");
+ return;
+ }
+}
+
+ProcessMonitor::~ProcessMonitor()
+{
+ StopMonitor();
+}
+
+//------------------------------------------------------------------------------
+// Thread setup and tear down.
+void
+ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error)
+{
+ static const char *g_thread_name = "lldb.process.freebsd.operation";
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, LaunchOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::LaunchOpThread(void *arg)
+{
+ LaunchArgs *args = static_cast<LaunchArgs*>(arg);
+
+ if (!Launch(args)) {
+ sem_post(&args->m_semaphore);
+ return NULL;
+ }
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Launch(LaunchArgs *args)
+{
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+ lldb::ProcessSP processSP = process.shared_from_this();
+ const char **argv = args->m_argv;
+ const char **envp = args->m_envp;
+ const char *stdin_path = args->m_stdin_path;
+ const char *stdout_path = args->m_stdout_path;
+ const char *stderr_path = args->m_stderr_path;
+ const char *working_dir = args->m_working_dir;
+
+ lldb_utility::PseudoTerminal terminal;
+ const size_t err_len = 1024;
+ char err_str[err_len];
+ lldb::pid_t pid;
+
+ lldb::ThreadSP inferior;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // Propagate the environment if one is not supplied.
+ if (envp == NULL || envp[0] == NULL)
+ envp = const_cast<const char **>(environ);
+
+ // Pseudo terminal setup.
+ if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len))
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Could not open controlling TTY.");
+ goto FINISH;
+ }
+
+ if ((pid = terminal.Fork(err_str, err_len)) == -1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Process fork failed.");
+ goto FINISH;
+ }
+
+ // Recognized child exit status codes.
+ enum {
+ ePtraceFailed = 1,
+ eDupStdinFailed,
+ eDupStdoutFailed,
+ eDupStderrFailed,
+ eChdirFailed,
+ eExecFailed
+ };
+
+ // Child process.
+ if (pid == 0)
+ {
+ // Trace this process.
+ if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0)
+ exit(ePtraceFailed);
+
+ // Do not inherit setgid powers.
+ setgid(getgid());
+
+ // Let us have our own process group.
+ setpgid(0, 0);
+
+ // Dup file descriptors if needed.
+ //
+ // FIXME: If two or more of the paths are the same we needlessly open
+ // the same file multiple times.
+ if (stdin_path != NULL && stdin_path[0])
+ if (!DupDescriptor(stdin_path, STDIN_FILENO, O_RDONLY))
+ exit(eDupStdinFailed);
+
+ if (stdout_path != NULL && stdout_path[0])
+ if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStdoutFailed);
+
+ if (stderr_path != NULL && stderr_path[0])
+ if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStderrFailed);
+
+ // Change working directory
+ if (working_dir != NULL && working_dir[0])
+ if (0 != ::chdir(working_dir))
+ exit(eChdirFailed);
+
+ // Execute. We should never return.
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ exit(eExecFailed);
+ }
+
+ // Wait for the child process to to trap on its call to execve.
+ ::pid_t wpid;
+ int status;
+ if ((wpid = waitpid(pid, &status, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ else if (WIFEXITED(status))
+ {
+ // open, dup or execve likely failed for some reason.
+ args->m_error.SetErrorToGenericError();
+ switch (WEXITSTATUS(status))
+ {
+ case ePtraceFailed:
+ args->m_error.SetErrorString("Child ptrace failed.");
+ break;
+ case eDupStdinFailed:
+ args->m_error.SetErrorString("Child open stdin failed.");
+ break;
+ case eDupStdoutFailed:
+ args->m_error.SetErrorString("Child open stdout failed.");
+ break;
+ case eDupStderrFailed:
+ args->m_error.SetErrorString("Child open stderr failed.");
+ break;
+ case eChdirFailed:
+ args->m_error.SetErrorString("Child failed to set working directory.");
+ break;
+ case eExecFailed:
+ args->m_error.SetErrorString("Child exec failed.");
+ break;
+ default:
+ args->m_error.SetErrorString("Child returned unknown exit status.");
+ break;
+ }
+ goto FINISH;
+ }
+ assert(WIFSTOPPED(status) && wpid == pid &&
+ "Could not sync with inferior process.");
+
+#ifdef notyet
+ // Have the child raise an event on exit. This is used to keep the child in
+ // limbo until it is destroyed.
+ if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+#endif
+ // Release the master terminal descriptor and pass it off to the
+ // ProcessMonitor instance. Similarly stash the inferior pid.
+ monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ monitor->m_pid = pid;
+
+ // Set the terminal fd to be in non blocking mode (it simplifies the
+ // implementation of ProcessFreeBSD::GetSTDOUT to have a non-blocking
+ // descriptor to read from).
+ if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
+ goto FINISH;
+
+ // Update the process thread list with this new thread.
+ inferior.reset(process.CreateNewPOSIXThread(*processSP, pid));
+ if (log)
+ log->Printf ("ProcessMonitor::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
+ process.GetThreadList().AddThread(inferior);
+
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+
+FINISH:
+ return args->m_error.Success();
+}
+
+bool
+ProcessMonitor::EnableIPC()
+{
+ int fd[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd))
+ return false;
+
+ m_client_fd = fd[0];
+ m_server_fd = fd[1];
+ return true;
+}
+
+void
+ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
+{
+ static const char *g_thread_name = "lldb.process.freebsd.operation";
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::AttachOpThread(void *arg)
+{
+ AttachArgs *args = static_cast<AttachArgs*>(arg);
+
+ if (!Attach(args))
+ return NULL;
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Attach(AttachArgs *args)
+{
+ lldb::pid_t pid = args->m_pid;
+
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+ lldb::ProcessSP processSP = process.shared_from_this();
+ ThreadList &tl = process.GetThreadList();
+ lldb::ThreadSP inferior;
+
+ if (pid <= 1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
+ goto FINISH;
+ }
+
+ // Attach to the requested process.
+ if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ int status;
+ if ((status = waitpid(pid, NULL, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ // Update the process thread list with the attached thread.
+ inferior.reset(process.CreateNewPOSIXThread(*processSP, pid));
+ tl.AddThread(inferior);
+
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+
+ FINISH:
+ return args->m_error.Success();
+}
+
+bool
+ProcessMonitor::MonitorCallback(void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status)
+{
+ ProcessMessage message;
+ ProcessMonitor *monitor = static_cast<ProcessMonitor*>(callback_baton);
+ ProcessFreeBSD *process = monitor->m_process;
+ assert(process);
+ bool stop_monitoring;
+ struct ptrace_lwpinfo plwp;
+ int ptrace_err;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (exited)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Exit(pid, status);
+ process->SendMessage(message);
+ return pid == process->GetID();
+ }
+
+ if (!monitor->GetLwpInfo(pid, &plwp, ptrace_err))
+ stop_monitoring = true; // pid is gone. Bail.
+ else {
+ switch (plwp.pl_siginfo.si_signo)
+ {
+ case SIGTRAP:
+ message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, pid);
+ break;
+
+ default:
+ message = MonitorSignal(monitor, &plwp.pl_siginfo, pid);
+ break;
+ }
+
+ process->SendMessage(message);
+ stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage;
+ }
+
+ return stop_monitoring;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid)
+{
+ ProcessMessage message;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ assert(monitor);
+ assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "Unexpected SIGTRAP code!");
+ break;
+
+ case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */):
+ {
+ // The inferior process is about to exit. Maintain the process in a
+ // state of "limbo" until we are explicitly commanded to detach,
+ // destroy, resume, etc.
+ unsigned long data = 0;
+ if (!monitor->GetEventMessage(pid, &data))
+ data = -1;
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
+ message = ProcessMessage::Limbo(pid, (data >> 8));
+ break;
+ }
+
+ case 0:
+ case TRAP_TRACE:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Trace(pid);
+ break;
+
+ case SI_KERNEL:
+ case TRAP_BRKPT:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Break(pid);
+ break;
+ }
+
+ return message;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid)
+{
+ ProcessMessage message;
+ int signo = info->si_signo;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
+ // kill(2) or raise(3). Similarly for tgkill(2) on FreeBSD.
+ //
+ // IOW, user generated signals never generate what we consider to be a
+ // "crash".
+ //
+ // Similarly, ACK signals generated by this monitor.
+ if (info->si_code == SI_USER)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d",
+ __FUNCTION__,
+ monitor->m_process->GetUnixSignals().GetSignalAsCString (signo),
+ "SI_USER",
+ info->si_pid);
+ if (info->si_pid == getpid())
+ return ProcessMessage::SignalDelivered(pid, signo);
+ else
+ return ProcessMessage::Signal(pid, signo);
+ }
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo));
+
+ if (signo == SIGSEGV) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGILL) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGFPE) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGBUS) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ // Everything else is "normal" and does not require any special action on
+ // our part.
+ return ProcessMessage::Signal(pid, signo);
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGSEGV(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGSEGV);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGSEGV");
+ break;
+ case SEGV_MAPERR:
+ reason = ProcessMessage::eInvalidAddress;
+ break;
+ case SEGV_ACCERR:
+ reason = ProcessMessage::ePrivilegedAddress;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGILL(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGILL);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGILL");
+ break;
+ case ILL_ILLOPC:
+ reason = ProcessMessage::eIllegalOpcode;
+ break;
+ case ILL_ILLOPN:
+ reason = ProcessMessage::eIllegalOperand;
+ break;
+ case ILL_ILLADR:
+ reason = ProcessMessage::eIllegalAddressingMode;
+ break;
+ case ILL_ILLTRP:
+ reason = ProcessMessage::eIllegalTrap;
+ break;
+ case ILL_PRVOPC:
+ reason = ProcessMessage::ePrivilegedOpcode;
+ break;
+ case ILL_PRVREG:
+ reason = ProcessMessage::ePrivilegedRegister;
+ break;
+ case ILL_COPROC:
+ reason = ProcessMessage::eCoprocessorError;
+ break;
+ case ILL_BADSTK:
+ reason = ProcessMessage::eInternalStackError;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGFPE(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGFPE);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGFPE");
+ break;
+ case FPE_INTDIV:
+ reason = ProcessMessage::eIntegerDivideByZero;
+ break;
+ case FPE_INTOVF:
+ reason = ProcessMessage::eIntegerOverflow;
+ break;
+ case FPE_FLTDIV:
+ reason = ProcessMessage::eFloatDivideByZero;
+ break;
+ case FPE_FLTOVF:
+ reason = ProcessMessage::eFloatOverflow;
+ break;
+ case FPE_FLTUND:
+ reason = ProcessMessage::eFloatUnderflow;
+ break;
+ case FPE_FLTRES:
+ reason = ProcessMessage::eFloatInexactResult;
+ break;
+ case FPE_FLTINV:
+ reason = ProcessMessage::eFloatInvalidOperation;
+ break;
+ case FPE_FLTSUB:
+ reason = ProcessMessage::eFloatSubscriptRange;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGBUS(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGBUS);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGBUS");
+ break;
+ case BUS_ADRALN:
+ reason = ProcessMessage::eIllegalAlignment;
+ break;
+ case BUS_ADRERR:
+ reason = ProcessMessage::eIllegalAddress;
+ break;
+ case BUS_OBJERR:
+ reason = ProcessMessage::eHardwareError;
+ break;
+ }
+
+ return reason;
+}
+
+void
+ProcessMonitor::ServeOperation(OperationArgs *args)
+{
+ int status;
+ pollfd fdset;
+
+ ProcessMonitor *monitor = args->m_monitor;
+
+ fdset.fd = monitor->m_server_fd;
+ fdset.events = POLLIN | POLLPRI;
+ fdset.revents = 0;
+
+ // We are finised with the arguments and are ready to go. Sync with the
+ // parent thread and start serving operations on the inferior.
+ sem_post(&args->m_semaphore);
+
+ for (;;)
+ {
+ if ((status = poll(&fdset, 1, -1)) < 0)
+ {
+ switch (errno)
+ {
+ default:
+ assert(false && "Unexpected poll() failure!");
+ continue;
+
+ case EINTR: continue; // Just poll again.
+ case EBADF: return; // Connection terminated.
+ }
+ }
+
+ assert(status == 1 && "Too many descriptors!");
+
+ if (fdset.revents & POLLIN)
+ {
+ Operation *op = NULL;
+
+ READ_AGAIN:
+ if ((status = read(fdset.fd, &op, sizeof(op))) < 0)
+ {
+ // There is only one acceptable failure.
+ assert(errno == EINTR);
+ goto READ_AGAIN;
+ }
+ if (status == 0)
+ continue; // Poll again. The connection probably terminated.
+ assert(status == sizeof(op));
+ op->Execute(monitor);
+ write(fdset.fd, &op, sizeof(op));
+ }
+ }
+}
+
+void
+ProcessMonitor::DoOperation(Operation *op)
+{
+ int status;
+ Operation *ack = NULL;
+ Mutex::Locker lock(m_server_mutex);
+
+ // FIXME: Do proper error checking here.
+ write(m_client_fd, &op, sizeof(op));
+
+READ_AGAIN:
+ if ((status = read(m_client_fd, &ack, sizeof(ack))) < 0)
+ {
+ // If interrupted by a signal handler try again. Otherwise the monitor
+ // thread probably died and we have a stale file descriptor -- abort the
+ // operation.
+ if (errno == EINTR)
+ goto READ_AGAIN;
+ return;
+ }
+
+ assert(status == sizeof(ack));
+ assert(ack == op && "Invalid monitor thread response!");
+}
+
+size_t
+ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ size_t result;
+ ReadOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+size_t
+ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error)
+{
+ size_t result;
+ WriteOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char* reg_name,
+ unsigned size, RegisterValue &value)
+{
+ bool result;
+ ReadRegOperation op(tid, offset, size, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char* reg_name, const RegisterValue &value)
+{
+ bool result;
+ WriteRegOperation op(tid, offset, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
+ m_process->GetUnixSignals().GetSignalAsCString (signo));
+ ResumeOperation op(tid, signo, result);
+ DoOperation(&op);
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
+ return result;
+}
+
+bool
+ProcessMonitor::SingleStep(lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ SingleStepOperation op(tid, signo, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::BringProcessIntoLimbo()
+{
+ bool result;
+ KillOperation op(result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err)
+{
+ bool result;
+ LwpInfoOperation op(tid, lwpinfo, result, ptrace_err);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+ bool result;
+ EventMessageOperation op(tid, message, result);
+ DoOperation(&op);
+ return result;
+}
+
+lldb_private::Error
+ProcessMonitor::Detach(lldb::tid_t tid)
+{
+ lldb_private::Error error;
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ DetachOperation op(error);
+ DoOperation(&op);
+ }
+ return error;
+}
+
+bool
+ProcessMonitor::DupDescriptor(const char *path, int fd, int flags)
+{
+ int target_fd = open(path, flags, 0666);
+
+ if (target_fd == -1)
+ return false;
+
+ return (dup2(target_fd, fd) == -1) ? false : true;
+}
+
+void
+ProcessMonitor::StopMonitoringChildProcess()
+{
+ lldb::thread_result_t thread_result;
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ Host::ThreadCancel(m_monitor_thread, NULL);
+ Host::ThreadJoin(m_monitor_thread, &thread_result, NULL);
+ m_monitor_thread = LLDB_INVALID_HOST_THREAD;
+ }
+}
+
+void
+ProcessMonitor::StopMonitor()
+{
+ StopMonitoringChildProcess();
+ StopOpThread();
+ CloseFD(m_terminal_fd);
+ CloseFD(m_client_fd);
+ CloseFD(m_server_fd);
+}
+
+void
+ProcessMonitor::StopOpThread()
+{
+ lldb::thread_result_t result;
+
+ if (!IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ Host::ThreadCancel(m_operation_thread, NULL);
+ Host::ThreadJoin(m_operation_thread, &result, NULL);
+ m_operation_thread = LLDB_INVALID_HOST_THREAD;
+}
+
+void
+ProcessMonitor::CloseFD(int &fd)
+{
+ if (fd != -1)
+ {
+ close(fd);
+ fd = -1;
+ }
+}
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
new file mode 100644
index 000000000000..ce66c03f2f8c
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -0,0 +1,322 @@
+//===-- ProcessMonitor.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_ProcessMonitor_H_
+#define liblldb_ProcessMonitor_H_
+
+// C Includes
+#include <semaphore.h>
+#include <signal.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private
+{
+class Error;
+class Module;
+class Scalar;
+} // End lldb_private namespace.
+
+class ProcessFreeBSD;
+class Operation;
+
+/// @class ProcessMonitor
+/// @brief Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process for
+/// debugging.
+///
+/// Changes in the inferior process state are propagated to the associated
+/// ProcessFreeBSD instance by calling ProcessFreeBSD::SendMessage with the
+/// appropriate ProcessMessage events.
+///
+/// A purposely minimal set of operations are provided to interrogate and change
+/// the inferior process state.
+class ProcessMonitor
+{
+public:
+
+ /// Launches an inferior process ready for debugging. Forms the
+ /// implementation of Process::DoLaunch.
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb_private::Module *module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ lldb_private::Error &error);
+
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb::pid_t pid,
+ lldb_private::Error &error);
+
+ ~ProcessMonitor();
+
+ /// Provides the process number of debugee.
+ lldb::pid_t
+ GetPID() const { return m_pid; }
+
+ /// Returns the process associated with this ProcessMonitor.
+ ProcessFreeBSD &
+ GetProcess() { return *m_process; }
+
+ /// Returns a file descriptor to the controlling terminal of the inferior
+ /// process.
+ ///
+ /// Reads from this file descriptor yield both the standard output and
+ /// standard error of this debugee. Even if stderr and stdout were
+ /// redirected on launch it may still happen that data is available on this
+ /// descriptor (if the inferior process opens /dev/tty, for example).
+ ///
+ /// If this monitor was attached to an existing process this method returns
+ /// -1.
+ int
+ GetTerminalFD() const { return m_terminal_fd; }
+
+ /// Reads @p size bytes from address @vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoReadMemory.
+ size_t
+ ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Writes @p size bytes from address @p vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoWriteMemory.
+ size_t
+ WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Reads the contents from the register identified by the given (architecture
+ /// dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ unsigned size, lldb_private::RegisterValue &value);
+
+ /// Writes the given value to the register identified by the given
+ /// (architecture dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ const lldb_private::RegisterValue &value);
+
+ /// Reads all general purpose registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads all floating point registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes all general purpose registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes all floating point registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID
+ /// to the memory region pointed to by @p lwpinfo.
+ bool
+ GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no);
+
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread IDto the memory pointed to by @p
+ /// message.
+ bool
+ GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ /// Resumes the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ Resume(lldb::tid_t tid, uint32_t signo);
+
+ /// Single steps the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ SingleStep(lldb::tid_t tid, uint32_t signo);
+
+ /// Sends the inferior process a PTRACE_KILL signal. The inferior will
+ /// still exists and can be interrogated. Once resumed it will exit as
+ /// though it received a SIGKILL.
+ bool
+ BringProcessIntoLimbo();
+
+ lldb_private::Error
+ Detach(lldb::tid_t tid);
+
+ void
+ StopMonitor();
+
+private:
+ ProcessFreeBSD *m_process;
+
+ lldb::thread_t m_operation_thread;
+ lldb::thread_t m_monitor_thread;
+ lldb::pid_t m_pid;
+
+
+ lldb_private::Mutex m_server_mutex;
+ int m_terminal_fd;
+ int m_client_fd;
+ int m_server_fd;
+
+ struct OperationArgs
+ {
+ OperationArgs(ProcessMonitor *monitor);
+
+ ~OperationArgs();
+
+ ProcessMonitor *m_monitor; // The monitor performing the attach.
+ sem_t m_semaphore; // Posted to once operation complete.
+ lldb_private::Error m_error; // Set if process operation failed.
+ };
+
+ /// @class LauchArgs
+ ///
+ /// @brief Simple structure to pass data to the thread responsible for
+ /// launching a child process.
+ struct LaunchArgs : OperationArgs
+ {
+ LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir);
+
+ ~LaunchArgs();
+
+ lldb_private::Module *m_module; // The executable image to launch.
+ char const **m_argv; // Process arguments.
+ char const **m_envp; // Process environment.
+ const char *m_stdin_path; // Redirect stdin or NULL.
+ const char *m_stdout_path; // Redirect stdout or NULL.
+ const char *m_stderr_path; // Redirect stderr or NULL.
+ const char *m_working_dir; // Working directory or NULL.
+ };
+
+ void
+ StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
+
+ static void *
+ LaunchOpThread(void *arg);
+
+ static bool
+ Launch(LaunchArgs *args);
+
+ bool
+ EnableIPC();
+
+ struct AttachArgs : OperationArgs
+ {
+ AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid);
+
+ ~AttachArgs();
+
+ lldb::pid_t m_pid; // pid of the process to be attached.
+ };
+
+ void
+ StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+
+ static void *
+ AttachOpThread(void *args);
+
+ static bool
+ Attach(AttachArgs *args);
+
+ static void
+ ServeOperation(OperationArgs *args);
+
+ static bool
+ DupDescriptor(const char *path, int fd, int flags);
+
+ static bool
+ MonitorCallback(void *callback_baton,
+ lldb::pid_t pid, bool exited, int signal, int status);
+
+ static ProcessMessage
+ MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ static ProcessMessage
+ MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGSEGV(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGILL(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGFPE(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGBUS(const siginfo_t *info);
+
+ void
+ DoOperation(Operation *op);
+
+ /// Stops the child monitor thread.
+ void
+ StopMonitoringChildProcess();
+
+ /// Stops the operation thread used to attach/launch a process.
+ void
+ StopOpThread();
+
+ void
+ CloseFD(int &fd);
+};
+
+#endif // #ifndef liblldb_ProcessMonitor_H_
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
new file mode 100644
index 000000000000..6e2c140682ba
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
@@ -0,0 +1,89 @@
+//===-- POSIXStopInfo.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "POSIXStopInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//===----------------------------------------------------------------------===//
+// POSIXLimboStopInfo
+
+POSIXLimboStopInfo::~POSIXLimboStopInfo() { }
+
+lldb::StopReason
+POSIXLimboStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonThreadExiting;
+}
+
+const char *
+POSIXLimboStopInfo::GetDescription()
+{
+ return "thread exiting";
+}
+
+bool
+POSIXLimboStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXLimboStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXCrashStopInfo
+
+POSIXCrashStopInfo::~POSIXCrashStopInfo() { }
+
+lldb::StopReason
+POSIXCrashStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonException;
+}
+
+const char *
+POSIXCrashStopInfo::GetDescription()
+{
+ return ProcessMessage::GetCrashReasonString(m_crash_reason, m_fault_addr);
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXNewThreadStopInfo
+
+POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { }
+
+lldb::StopReason
+POSIXNewThreadStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonNone;
+}
+
+const char *
+POSIXNewThreadStopInfo::GetDescription()
+{
+ return "thread spawned";
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.h b/source/Plugins/Process/POSIX/POSIXStopInfo.h
new file mode 100644
index 000000000000..cbf309e53506
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.h
@@ -0,0 +1,120 @@
+//===-- POSIXStopInfo.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_POSIXStopInfo_H_
+#define liblldb_POSIXStopInfo_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+#include "POSIXThread.h"
+#include "ProcessMessage.h"
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXStopInfo
+/// @brief Simple base class for all POSIX-specific StopInfo objects.
+///
+class POSIXStopInfo
+ : public lldb_private::StopInfo
+{
+public:
+ POSIXStopInfo(lldb_private::Thread &thread, uint32_t status)
+ : StopInfo(thread, status)
+ { }
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXLimboStopInfo
+/// @brief Represents the stop state of a process ready to exit.
+///
+class POSIXLimboStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXLimboStopInfo(POSIXThread &thread)
+ : POSIXStopInfo(thread, 0)
+ { }
+
+ ~POSIXLimboStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXCrashStopInfo
+/// @brief Represents the stop state of process that is ready to crash.
+///
+class POSIXCrashStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXCrashStopInfo(POSIXThread &thread, uint32_t status,
+ ProcessMessage::CrashReason reason,
+ lldb::addr_t fault_addr)
+ : POSIXStopInfo(thread, status),
+ m_crash_reason(reason),
+ m_fault_addr(fault_addr)
+ { }
+
+ ~POSIXCrashStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+private:
+ ProcessMessage::CrashReason m_crash_reason;
+ lldb::addr_t m_fault_addr;
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXNewThreadStopInfo
+/// @brief Represents the stop state of process when a new thread is spawned.
+///
+
+class POSIXNewThreadStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXNewThreadStopInfo (POSIXThread &thread)
+ : POSIXStopInfo (thread, 0)
+ { }
+
+ ~POSIXNewThreadStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp
new file mode 100644
index 000000000000..93c296679df2
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXThread.cpp
@@ -0,0 +1,578 @@
+//===-- POSIXThread.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/lldb-python.h"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "POSIXStopInfo.h"
+#include "POSIXThread.h"
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86_64.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContextLinux_x86_64.h"
+#include "RegisterContextFreeBSD_x86_64.h"
+
+#include "UnwindLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+POSIXThread::POSIXThread(Process &process, lldb::tid_t tid)
+ : Thread(process, tid),
+ m_frame_ap (),
+ m_breakpoint (),
+ m_thread_name_valid (false),
+ m_thread_name ()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid);
+
+ // Set the current watchpoints for this thread.
+ Target &target = GetProcess()->GetTarget();
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ size_t wp_size = wp_list.GetSize();
+
+ for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++)
+ {
+ lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx);
+ if (wp.get() && wp->IsEnabled())
+ {
+ assert(EnableHardwareWatchpoint(wp.get()));
+ }
+ }
+}
+
+POSIXThread::~POSIXThread()
+{
+ DestroyThread();
+}
+
+ProcessMonitor &
+POSIXThread::GetMonitor()
+{
+ ProcessSP base = GetProcess();
+ ProcessPOSIX &process = static_cast<ProcessPOSIX&>(*base);
+ return process.GetMonitor();
+}
+
+void
+POSIXThread::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The KDPRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ //if (StateIsStoppedState(GetState())
+ {
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+ }
+ // FIXME: This should probably happen somewhere else.
+ SetResumeState(eStateRunning);
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID());
+}
+
+const char *
+POSIXThread::GetInfo()
+{
+ return NULL;
+}
+
+void
+POSIXThread::SetName (const char *name)
+{
+ m_thread_name_valid = (name && name[0]);
+ if (m_thread_name_valid)
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+}
+
+const char *
+POSIXThread::GetName ()
+{
+ if (!m_thread_name_valid)
+ {
+ SetName(Host::GetThreadName(GetProcess()->GetID(), GetID()).c_str());
+ m_thread_name_valid = true;
+ }
+
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+lldb::RegisterContextSP
+POSIXThread::GetRegisterContext()
+{
+ if (!m_reg_context_sp)
+ {
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ m_reg_context_sp.reset(new RegisterContext_i386(*this, 0));
+ break;
+
+ case ArchSpec::eCore_x86_64_x86_64:
+ switch (arch.GetTriple().getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ m_reg_context_sp.reset(new RegisterContextFreeBSD_x86_64(*this, 0));
+ break;
+ case llvm::Triple::Linux:
+ m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0));
+ break;
+ default:
+ assert(false && "OS not supported");
+ break;
+ }
+ break;
+ }
+ }
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s ()", __FUNCTION__);
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0)
+ reg_ctx_sp = GetRegisterContext();
+ else
+ {
+ assert(GetUnwinder());
+ reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame);
+ }
+
+ return reg_ctx_sp;
+}
+
+bool
+POSIXThread::CalculateStopInfo()
+{
+ SetStopInfo (m_stop_info_sp);
+ return true;
+}
+
+Unwind *
+POSIXThread::GetUnwinder()
+{
+ if (m_unwinder_ap.get() == NULL)
+ m_unwinder_ap.reset(new UnwindLLDB(*this));
+
+ return m_unwinder_ap.get();
+}
+
+void
+POSIXThread::WillResume(lldb::StateType resume_state)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state));
+ // TODO: the line below shouldn't really be done, but
+ // the POSIXThread might rely on this so I will leave this in for now
+ SetResumeState(resume_state);
+}
+
+void
+POSIXThread::DidStop()
+{
+ // Don't set the thread state to stopped unless we really stopped.
+}
+
+bool
+POSIXThread::Resume()
+{
+ lldb::StateType resume_state = GetResumeState();
+ ProcessMonitor &monitor = GetMonitor();
+ bool status;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__,
+ StateAsCString(resume_state));
+
+ switch (resume_state)
+ {
+ default:
+ assert(false && "Unexpected state for resume!");
+ status = false;
+ break;
+
+ case lldb::eStateRunning:
+ SetState(resume_state);
+ status = monitor.Resume(GetID(), GetResumeSignal());
+ break;
+
+ case lldb::eStateStepping:
+ SetState(resume_state);
+ status = monitor.SingleStep(GetID(), GetResumeSignal());
+ break;
+ case lldb::eStateStopped:
+ case lldb::eStateSuspended:
+ status = true;
+ break;
+ }
+
+ return status;
+}
+
+void
+POSIXThread::Notify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () message kind = '%s' for tid %" PRIu64,
+ __FUNCTION__, message.PrintKind(), GetID());
+
+ switch (message.GetKind())
+ {
+ default:
+ assert(false && "Unexpected message kind!");
+ break;
+
+ case ProcessMessage::eExitMessage:
+ // Nothing to be done.
+ break;
+
+ case ProcessMessage::eLimboMessage:
+ LimboNotify(message);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ SignalNotify(message);
+ break;
+
+ case ProcessMessage::eSignalDeliveredMessage:
+ SignalDeliveredNotify(message);
+ break;
+
+ case ProcessMessage::eTraceMessage:
+ TraceNotify(message);
+ break;
+
+ case ProcessMessage::eBreakpointMessage:
+ BreakNotify(message);
+ break;
+
+ case ProcessMessage::eWatchpointMessage:
+ WatchNotify(message);
+ break;
+
+ case ProcessMessage::eCrashMessage:
+ CrashNotify(message);
+ break;
+
+ case ProcessMessage::eNewThreadMessage:
+ ThreadNotify(message);
+ break;
+ }
+}
+
+bool
+POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool wp_set = false;
+ if (wp)
+ {
+ addr_t wp_addr = wp->GetLoadAddress();
+ size_t wp_size = wp->GetByteSize();
+ bool wp_read = wp->WatchpointRead();
+ bool wp_write = wp->WatchpointWrite();
+ uint32_t wp_hw_index = wp->GetHardwareIndex();
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size,
+ wp_read, wp_write,
+ wp_hw_index);
+ }
+ return wp_set;
+}
+
+bool
+POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool result = false;
+ if (wp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ }
+ return result;
+}
+
+uint32_t
+POSIXThread::NumSupportedHardwareWatchpoints()
+{
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+POSIXThread::FindVacantWatchpointIndex()
+{
+ uint32_t hw_index = LLDB_INVALID_INDEX32;
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointVacant(wp_idx))
+ {
+ hw_index = wp_idx;
+ break;
+ }
+ }
+ }
+ return hw_index;
+}
+
+void
+POSIXThread::BreakNotify(const ProcessMessage &message)
+{
+ bool status;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ assert(GetRegisterContext());
+ status = GetRegisterContextPOSIX()->UpdateAfterBreakpoint();
+ assert(status && "Breakpoint update failed!");
+
+ // With our register state restored, resolve the breakpoint object
+ // corresponding to our current PC.
+ assert(GetRegisterContext());
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ if (log)
+ log->Printf ("POSIXThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
+ lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site && bp_site->ValidForThisThread(this))
+ {
+ lldb::break_id_t bp_id = bp_site->GetID();
+ if (GetProcess()->GetThreadList().SetSelectedThreadByID(GetID()))
+ SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
+ else
+ assert(false && "Invalid thread ID during BreakNotify.");
+ }
+ else
+ {
+ const ThreadSpec *spec = bp_site ?
+ bp_site->GetOwnerAtIndex(0)->GetOptionsNoCreate()->GetThreadSpecNoCreate() : 0;
+
+ if (spec && spec->TIDMatches(*this))
+ assert(false && "BreakpointSite is invalid for the current ThreadSpec.");
+ else
+ {
+ if (!m_stop_info_sp) {
+ StopInfoSP invalid_stop_info_sp;
+ SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ }
+}
+
+void
+POSIXThread::WatchNotify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ lldb::addr_t halt_addr = message.GetHWAddress();
+ if (log)
+ log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8"
+ PRIx64, __FUNCTION__, halt_addr);
+
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointHit(wp_idx))
+ {
+ // Clear the watchpoint hit here
+ reg_ctx->ClearWatchpointHits();
+ break;
+ }
+ }
+
+ if (wp_idx == num_hw_wps)
+ return;
+
+ Target &target = GetProcess()->GetTarget();
+ lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
+
+ assert(wp_sp.get() && "No watchpoint found");
+ SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this,
+ wp_sp->GetID()));
+ }
+}
+
+void
+POSIXThread::TraceNotify(const ProcessMessage &message)
+{
+ SetStopInfo (StopInfo::CreateStopReasonToTrace(*this));
+}
+
+void
+POSIXThread::LimboNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this)));
+}
+
+void
+POSIXThread::SignalNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::SignalDeliveredNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::CrashNotify(const ProcessMessage &message)
+{
+ // FIXME: Update stop reason as per bugzilla 14598
+ int signo = message.GetSignal();
+
+ assert(message.GetKind() == ProcessMessage::eCrashMessage);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () signo = %i, reason = '%s'",
+ __FUNCTION__, signo, message.PrintCrashReason());
+
+ SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo,
+ message.GetCrashReason(),
+ message.GetFaultAddress())));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::ThreadNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this)));
+}
+
+unsigned
+POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg = LLDB_INVALID_REGNUM;
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ llvm_unreachable("CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ RegisterContextSP base = GetRegisterContext();
+ if (base) {
+ RegisterContextPOSIX &context = static_cast<RegisterContextPOSIX &>(*base);
+ reg = context.GetRegisterIndexFromOffset(offset);
+ }
+ }
+ break;
+ }
+ return reg;
+}
+
+const char *
+POSIXThread::GetRegisterName(unsigned reg)
+{
+ const char * name = nullptr;
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ name = GetRegisterContext()->GetRegisterName(reg);
+ break;
+ }
+ return name;
+}
+
+const char *
+POSIXThread::GetRegisterNameFromOffset(unsigned offset)
+{
+ return GetRegisterName(GetRegisterIndexFromOffset(offset));
+}
+
diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/POSIX/POSIXThread.h
new file mode 100644
index 000000000000..d051d23860df
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXThread.h
@@ -0,0 +1,133 @@
+//===-- POSIXThread.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_POSIXThread_H_
+#define liblldb_POSIXThread_H_
+
+// C Includes
+// C++ Includes
+#include <memory>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Target/Thread.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMessage;
+class ProcessMonitor;
+class RegisterContextPOSIX;
+
+//------------------------------------------------------------------------------
+// @class POSIXThread
+// @brief Abstraction of a POSIX thread.
+class POSIXThread
+ : public lldb_private::Thread
+{
+public:
+ POSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual ~POSIXThread();
+
+ void
+ RefreshStateAfterStop();
+
+ virtual void
+ WillResume(lldb::StateType resume_state);
+
+ // This notifies the thread when a private stop occurs.
+ virtual void
+ DidStop ();
+
+ const char *
+ GetInfo();
+
+ void
+ SetName (const char *name);
+
+ const char *
+ GetName ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ //--------------------------------------------------------------------------
+ // These functions provide a mapping from the register offset
+ // back to the register index or name for use in debugging or log
+ // output.
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ const char *
+ GetRegisterNameFromOffset(unsigned offset);
+
+ //--------------------------------------------------------------------------
+ // These methods form a specialized interface to POSIX threads.
+ //
+ bool Resume();
+
+ void Notify(const ProcessMessage &message);
+
+ //--------------------------------------------------------------------------
+ // These methods provide an interface to watchpoints
+ //
+ bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ uint32_t NumSupportedHardwareWatchpoints();
+
+ uint32_t FindVacantWatchpointIndex();
+
+protected:
+ RegisterContextPOSIX *
+ GetRegisterContextPOSIX ()
+ {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = GetRegisterContext();
+#if 0
+ return dynamic_cast<RegisterContextPOSIX*>(m_reg_context_sp.get());
+#endif
+ return (RegisterContextPOSIX *)m_reg_context_sp.get();
+ }
+
+ std::unique_ptr<lldb_private::StackFrame> m_frame_ap;
+
+ lldb::BreakpointSiteSP m_breakpoint;
+
+ bool m_thread_name_valid;
+ std::string m_thread_name;
+
+ ProcessMonitor &
+ GetMonitor();
+
+ virtual bool
+ CalculateStopInfo();
+
+ void BreakNotify(const ProcessMessage &message);
+ void WatchNotify(const ProcessMessage &message);
+ virtual void TraceNotify(const ProcessMessage &message);
+ void LimboNotify(const ProcessMessage &message);
+ void SignalNotify(const ProcessMessage &message);
+ void SignalDeliveredNotify(const ProcessMessage &message);
+ void CrashNotify(const ProcessMessage &message);
+ void ThreadNotify(const ProcessMessage &message);
+ void ExitNotify(const ProcessMessage &message);
+
+ lldb_private::Unwind *
+ GetUnwinder();
+};
+
+#endif // #ifndef liblldb_POSIXThread_H_
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.cpp b/source/Plugins/Process/POSIX/ProcessMessage.cpp
new file mode 100644
index 000000000000..60a29e07cea8
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessMessage.cpp
@@ -0,0 +1,258 @@
+//===-- ProcessMessage.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMessage.h"
+
+#include <sstream>
+
+using namespace lldb_private;
+
+namespace {
+
+inline void AppendFaultAddr(std::string& str, lldb::addr_t addr)
+{
+ std::stringstream ss;
+ ss << " (fault address: 0x" << std::hex << addr << ")";
+ str += ss.str();
+}
+
+}
+
+const char *
+ProcessMessage::GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr)
+{
+ static std::string str;
+
+ switch (reason)
+ {
+ default:
+ assert(false && "invalid CrashReason");
+ break;
+
+ case eInvalidAddress:
+ str = "invalid address";
+ AppendFaultAddr(str, fault_addr);
+ break;
+ case ePrivilegedAddress:
+ str = "address access protected";
+ AppendFaultAddr(str, fault_addr);
+ break;
+ case eIllegalOpcode:
+ str = "illegal instruction";
+ break;
+ case eIllegalOperand:
+ str = "illegal instruction operand";
+ break;
+ case eIllegalAddressingMode:
+ str = "illegal addressing mode";
+ break;
+ case eIllegalTrap:
+ str = "illegal trap";
+ break;
+ case ePrivilegedOpcode:
+ str = "privileged instruction";
+ break;
+ case ePrivilegedRegister:
+ str = "privileged register";
+ break;
+ case eCoprocessorError:
+ str = "coprocessor error";
+ break;
+ case eInternalStackError:
+ str = "internal stack error";
+ break;
+ case eIllegalAlignment:
+ str = "illegal alignment";
+ break;
+ case eIllegalAddress:
+ str = "illegal address";
+ break;
+ case eHardwareError:
+ str = "hardware error";
+ break;
+ case eIntegerDivideByZero:
+ str = "integer divide by zero";
+ break;
+ case eIntegerOverflow:
+ str = "integer overflow";
+ break;
+ case eFloatDivideByZero:
+ str = "floating point divide by zero";
+ break;
+ case eFloatOverflow:
+ str = "floating point overflow";
+ break;
+ case eFloatUnderflow:
+ str = "floating point underflow";
+ break;
+ case eFloatInexactResult:
+ str = "inexact floating point result";
+ break;
+ case eFloatInvalidOperation:
+ str = "invalid floating point operation";
+ break;
+ case eFloatSubscriptRange:
+ str = "invalid floating point subscript range";
+ break;
+ }
+
+ return str.c_str();
+}
+
+const char *
+ProcessMessage::PrintCrashReason(CrashReason reason)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in asci for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = NULL;
+
+ switch (reason)
+ {
+ case eInvalidCrashReason:
+ str = "eInvalidCrashReason";
+ break;
+
+ // SIGSEGV crash reasons.
+ case eInvalidAddress:
+ str = "eInvalidAddress";
+ break;
+ case ePrivilegedAddress:
+ str = "ePrivilegedAddress";
+ break;
+
+ // SIGILL crash reasons.
+ case eIllegalOpcode:
+ str = "eIllegalOpcode";
+ break;
+ case eIllegalOperand:
+ str = "eIllegalOperand";
+ break;
+ case eIllegalAddressingMode:
+ str = "eIllegalAddressingMode";
+ break;
+ case eIllegalTrap:
+ str = "eIllegalTrap";
+ break;
+ case ePrivilegedOpcode:
+ str = "ePrivilegedOpcode";
+ break;
+ case ePrivilegedRegister:
+ str = "ePrivilegedRegister";
+ break;
+ case eCoprocessorError:
+ str = "eCoprocessorError";
+ break;
+ case eInternalStackError:
+ str = "eInternalStackError";
+ break;
+
+ // SIGBUS crash reasons:
+ case eIllegalAlignment:
+ str = "eIllegalAlignment";
+ break;
+ case eIllegalAddress:
+ str = "eIllegalAddress";
+ break;
+ case eHardwareError:
+ str = "eHardwareError";
+ break;
+
+ // SIGFPE crash reasons:
+ case eIntegerDivideByZero:
+ str = "eIntegerDivideByZero";
+ break;
+ case eIntegerOverflow:
+ str = "eIntegerOverflow";
+ break;
+ case eFloatDivideByZero:
+ str = "eFloatDivideByZero";
+ break;
+ case eFloatOverflow:
+ str = "eFloatOverflow";
+ break;
+ case eFloatUnderflow:
+ str = "eFloatUnderflow";
+ break;
+ case eFloatInexactResult:
+ str = "eFloatInexactResult";
+ break;
+ case eFloatInvalidOperation:
+ str = "eFloatInvalidOperation";
+ break;
+ case eFloatSubscriptRange:
+ str = "eFloatSubscriptRange";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+const char *
+ProcessMessage::PrintCrashReason() const
+{
+ return PrintCrashReason(m_crash_reason);
+}
+
+const char *
+ProcessMessage::PrintKind(Kind kind)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in asci for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = NULL;
+
+ switch (kind)
+ {
+ case eInvalidMessage:
+ str = "eInvalidMessage";
+ break;
+ case eExitMessage:
+ str = "eExitMessage";
+ break;
+ case eLimboMessage:
+ str = "eLimboMessage";
+ break;
+ case eSignalMessage:
+ str = "eSignalMessage";
+ break;
+ case eSignalDeliveredMessage:
+ str = "eSignalDeliveredMessage";
+ break;
+ case eTraceMessage:
+ str = "eTraceMessage";
+ break;
+ case eBreakpointMessage:
+ str = "eBreakpointMessage";
+ break;
+ case eWatchpointMessage:
+ str = "eWatchpointMessage";
+ break;
+ case eCrashMessage:
+ str = "eCrashMessage";
+ break;
+ case eNewThreadMessage:
+ str = "eNewThreadMessage";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+const char *
+ProcessMessage::PrintKind() const
+{
+ return PrintKind(m_kind);
+}
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.h b/source/Plugins/Process/POSIX/ProcessMessage.h
new file mode 100644
index 000000000000..c6c460c13445
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessMessage.h
@@ -0,0 +1,207 @@
+//===-- ProcessMessage.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_ProcessMessage_H_
+#define liblldb_ProcessMessage_H_
+
+#include <cassert>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+class ProcessMessage
+{
+public:
+
+ /// The type of signal this message can correspond to.
+ enum Kind
+ {
+ eInvalidMessage,
+ eExitMessage,
+ eLimboMessage,
+ eSignalMessage,
+ eSignalDeliveredMessage,
+ eTraceMessage,
+ eBreakpointMessage,
+ eWatchpointMessage,
+ eCrashMessage,
+ eNewThreadMessage
+ };
+
+ enum CrashReason
+ {
+ eInvalidCrashReason,
+
+ // SIGSEGV crash reasons.
+ eInvalidAddress,
+ ePrivilegedAddress,
+
+ // SIGILL crash reasons.
+ eIllegalOpcode,
+ eIllegalOperand,
+ eIllegalAddressingMode,
+ eIllegalTrap,
+ ePrivilegedOpcode,
+ ePrivilegedRegister,
+ eCoprocessorError,
+ eInternalStackError,
+
+ // SIGBUS crash reasons,
+ eIllegalAlignment,
+ eIllegalAddress,
+ eHardwareError,
+
+ // SIGFPE crash reasons,
+ eIntegerDivideByZero,
+ eIntegerOverflow,
+ eFloatDivideByZero,
+ eFloatOverflow,
+ eFloatUnderflow,
+ eFloatInexactResult,
+ eFloatInvalidOperation,
+ eFloatSubscriptRange
+ };
+
+ ProcessMessage()
+ : m_tid(LLDB_INVALID_PROCESS_ID),
+ m_kind(eInvalidMessage),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(0),
+ m_addr(0) { }
+
+ Kind GetKind() const { return m_kind; }
+
+ lldb::tid_t GetTID() const { return m_tid; }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Limbo(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eLimboMessage, status);
+ }
+
+ /// Indicates that the thread @p tid had the signal @p signum delivered.
+ static ProcessMessage Signal(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalMessage, signum);
+ }
+
+ /// Indicates that a signal @p signum generated by the debugging process was
+ /// delivered to the thread @p tid.
+ static ProcessMessage SignalDelivered(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalDeliveredMessage, signum);
+ }
+
+ /// Indicates that the thread @p tid encountered a trace point.
+ static ProcessMessage Trace(lldb::tid_t tid) {
+ return ProcessMessage(tid, eTraceMessage);
+ }
+
+ /// Indicates that the thread @p tid encountered a break point.
+ static ProcessMessage Break(lldb::tid_t tid) {
+ return ProcessMessage(tid, eBreakpointMessage);
+ }
+
+ static ProcessMessage Watch(lldb::tid_t tid, lldb::addr_t wp_addr) {
+ return ProcessMessage(tid, eWatchpointMessage, 0, wp_addr);
+ }
+
+ /// Indicates that the thread @p tid crashed.
+ static ProcessMessage Crash(lldb::pid_t pid, CrashReason reason,
+ int signo, lldb::addr_t fault_addr) {
+ ProcessMessage message(pid, eCrashMessage, signo, fault_addr);
+ message.m_crash_reason = reason;
+ return message;
+ }
+
+ /// Indicates that the thread @p child_tid was spawned.
+ static ProcessMessage NewThread(lldb::tid_t parent_tid, lldb::tid_t child_tid) {
+ return ProcessMessage(parent_tid, eNewThreadMessage, child_tid);
+ }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Exit(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eExitMessage, status);
+ }
+
+ int GetExitStatus() const {
+ assert(GetKind() == eExitMessage || GetKind() == eLimboMessage);
+ return m_status;
+ }
+
+ int GetSignal() const {
+ assert(GetKind() == eSignalMessage || GetKind() == eCrashMessage ||
+ GetKind() == eSignalDeliveredMessage);
+ return m_status;
+ }
+
+ int GetStopStatus() const {
+ assert(GetKind() == eSignalMessage);
+ return m_status;
+ }
+
+ CrashReason GetCrashReason() const {
+ assert(GetKind() == eCrashMessage);
+ return m_crash_reason;
+ }
+
+ lldb::addr_t GetFaultAddress() const {
+ assert(GetKind() == eCrashMessage);
+ return m_addr;
+ }
+
+ lldb::addr_t GetHWAddress() const {
+ assert(GetKind() == eWatchpointMessage || GetKind() == eTraceMessage);
+ return m_addr;
+ }
+
+ lldb::tid_t GetChildTID() const {
+ assert(GetKind() == eNewThreadMessage);
+ return m_child_tid;
+ }
+
+ static const char *
+ GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr);
+
+ const char *
+ PrintCrashReason() const;
+
+ static const char *
+ PrintCrashReason(CrashReason reason);
+
+ const char *
+ PrintKind() const;
+
+ static const char *
+ PrintKind(Kind);
+
+private:
+ ProcessMessage(lldb::tid_t tid, Kind kind,
+ int status = 0, lldb::addr_t addr = 0)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(status),
+ m_addr(addr),
+ m_child_tid(0) { }
+
+ ProcessMessage(lldb::tid_t tid, Kind kind, lldb::tid_t child_tid)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(0),
+ m_addr(0),
+ m_child_tid(child_tid) { }
+
+ lldb::tid_t m_tid;
+ Kind m_kind : 8;
+ CrashReason m_crash_reason : 8;
+ int m_status;
+ lldb::addr_t m_addr;
+ lldb::tid_t m_child_tid;
+};
+
+#endif // #ifndef liblldb_ProcessMessage_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
new file mode 100644
index 000000000000..f04631ddf914
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -0,0 +1,911 @@
+//===-- ProcessPOSIX.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/lldb-python.h"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "ProcessMonitor.h"
+#include "POSIXThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static functions.
+#if 0
+Process*
+ProcessPOSIX::CreateInstance(Target& target, Listener &listener)
+{
+ return new ProcessPOSIX(target, listener);
+}
+
+
+void
+ProcessPOSIX::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (!g_initialized)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+
+ Log::Callbacks log_callbacks = {
+ ProcessPOSIXLog::DisableLog,
+ ProcessPOSIXLog::EnableLog,
+ ProcessPOSIXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessPOSIX::GetPluginNameStatic(), log_callbacks);
+ }
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener)
+ : Process(target, listener),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_monitor(NULL),
+ m_module(NULL),
+ m_message_mutex (Mutex::eMutexTypeRecursive),
+ m_exit_now(false),
+ m_seen_initial_stop()
+{
+ // FIXME: Putting this code in the ctor and saving the byte order in a
+ // member variable is a hack to avoid const qual issues in GetByteOrder.
+ lldb::ModuleSP module = GetTarget().GetExecutableModule();
+ if (module && module->GetObjectFile())
+ m_byte_order = module->GetObjectFile()->GetByteOrder();
+}
+
+ProcessPOSIX::~ProcessPOSIX()
+{
+ delete m_monitor;
+}
+
+//------------------------------------------------------------------------------
+// Process protocol.
+void
+ProcessPOSIX::Finalize()
+{
+ Process::Finalize();
+
+ if (m_monitor)
+ m_monitor->StopMonitor();
+}
+
+bool
+ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+ // 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();
+ // If there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+Error
+ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ m_monitor = new ProcessMonitor(this, pid, error);
+
+ if (!error.Success())
+ return error;
+
+ PlatformSP platform_sp (m_target.GetPlatform ());
+ assert (platform_sp.get());
+ if (!platform_sp)
+ return error; // FIXME: Detatch?
+
+ // Find out what we can about this process
+ ProcessInstanceInfo process_info;
+ platform_sp->GetProcessInfo (pid, process_info);
+
+ // Resolve the executable module
+ ModuleSP exe_module_sp;
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+ error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(),
+ m_target.GetArchitecture(),
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ if (!error.Success())
+ return error;
+
+ // Fix the target architecture if necessary
+ const ArchSpec &module_arch = exe_module_sp->GetArchitecture();
+ if (module_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(module_arch))
+ m_target.SetArchitecture(module_arch);
+
+ // Initialize the target module list
+ m_target.SetExecutableModule (exe_module_sp, true);
+
+ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
+
+ SetID(pid);
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+{
+ return DoAttachToProcessWithID(pid);
+}
+
+Error
+ProcessPOSIX::WillLaunch(Module* module)
+{
+ Error error;
+ return error;
+}
+
+const char *
+ProcessPOSIX::GetFilePath(
+ const lldb_private::ProcessLaunchInfo::FileAction *file_action,
+ const char *default_path)
+{
+ const char *pts_name = "/dev/pts/";
+ const char *path = NULL;
+
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ path = file_action->GetPath();
+ // By default the stdio paths passed in will be pseudo-terminal
+ // (/dev/pts). If so, convert to using a different default path
+ // instead to redirect I/O to the debugger console. This should
+ // also handle user overrides to /dev/null or a different file.
+ if (::strncmp(path, pts_name, ::strlen(pts_name)) == 0)
+ path = default_path;
+ }
+
+ return path;
+}
+
+Error
+ProcessPOSIX::DoLaunch (Module *module,
+ const ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ const char* working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir) {
+ FileSpec WorkingDir(working_dir, true);
+ if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory)
+ {
+ error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
+ return error;
+ }
+ }
+
+ SetPrivateState(eStateLaunching);
+
+ const lldb_private::ProcessLaunchInfo::FileAction *file_action;
+
+ // Default of NULL will mean to use existing open file descriptors
+ const char *stdin_path = NULL;
+ const char *stdout_path = NULL;
+ const char *stderr_path = NULL;
+
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ stdin_path = GetFilePath(file_action, stdin_path);
+
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ stdout_path = GetFilePath(file_action, stdout_path);
+
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ stderr_path = GetFilePath(file_action, stderr_path);
+
+ m_monitor = new ProcessMonitor (this,
+ module,
+ launch_info.GetArguments().GetConstArgumentVector(),
+ launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
+ stdin_path,
+ stdout_path,
+ stderr_path,
+ working_dir,
+ error);
+
+ m_module = module;
+
+ if (!error.Success())
+ return error;
+
+ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
+
+ SetID(m_monitor->GetPID());
+ return error;
+}
+
+void
+ProcessPOSIX::DidLaunch()
+{
+}
+
+Error
+ProcessPOSIX::DoResume()
+{
+ StateType state = GetPrivateState();
+
+ assert(state == eStateStopped);
+
+ SetPrivateState(eStateRunning);
+
+ bool did_resume = false;
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ did_resume = thread->Resume() || did_resume;
+ }
+ assert(did_resume && "Process resume failed!");
+
+ return Error();
+}
+
+addr_t
+ProcessPOSIX::GetImageInfoAddress()
+{
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress();
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+ProcessPOSIX::DoHalt(bool &caused_stop)
+{
+ Error error;
+
+ if (IsStopped())
+ {
+ caused_stop = false;
+ }
+ else if (kill(GetID(), SIGSTOP))
+ {
+ caused_stop = false;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ caused_stop = true;
+ }
+ return error;
+}
+
+Error
+ProcessPOSIX::DoDetach(bool keep_stopped)
+{
+ Error error;
+ if (keep_stopped)
+ {
+ // FIXME: If you want to implement keep_stopped,
+ // this would be the place to do it.
+ error.SetErrorString("Detaching with keep_stopped true is not currently supported on this platform.");
+ return error;
+ }
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ error = m_monitor->Detach(thread->GetID());
+ }
+
+ if (error.Success())
+ SetPrivateState(eStateDetached);
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoSignal(int signal)
+{
+ Error error;
+
+ if (kill(GetID(), signal))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoDestroy()
+{
+ Error error;
+
+ if (!HasExited())
+ {
+ // Drive the exit event to completion (do not keep the inferior in
+ // limbo).
+ m_exit_now = true;
+
+ if ((m_monitor == NULL || kill(m_monitor->GetPID(), SIGKILL)) && error.Success())
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ SetPrivateState(eStateExited);
+ }
+
+ return error;
+}
+
+void
+ProcessPOSIX::SendMessage(const ProcessMessage &message)
+{
+ Mutex::Locker lock(m_message_mutex);
+
+ Mutex::Locker thread_lock(m_thread_list.GetMutex());
+
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.FindThreadByID(message.GetTID(), false).get());
+
+ switch (message.GetKind())
+ {
+ case ProcessMessage::eInvalidMessage:
+ return;
+
+ case ProcessMessage::eLimboMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ if (message.GetTID() == GetID())
+ {
+ m_exit_status = message.GetExitStatus();
+ if (m_exit_now)
+ {
+ SetPrivateState(eStateExited);
+ m_monitor->Detach(GetID());
+ }
+ else
+ {
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ }
+ }
+ else
+ {
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ }
+ break;
+
+ case ProcessMessage::eExitMessage:
+ assert(thread);
+ thread->SetState(eStateExited);
+ // FIXME: I'm not sure we need to do this.
+ if (message.GetTID() == GetID())
+ {
+ m_exit_status = message.GetExitStatus();
+ SetExitStatus(m_exit_status, NULL);
+ }
+ else if (!IsAThreadRunning())
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ case ProcessMessage::eSignalDeliveredMessage:
+ if (message.GetSignal() == SIGSTOP &&
+ AddThreadForInitialStopIfNeeded(message.GetTID()))
+ return;
+ // Intentional fall-through
+
+ case ProcessMessage::eBreakpointMessage:
+ case ProcessMessage::eTraceMessage:
+ case ProcessMessage::eWatchpointMessage:
+ case ProcessMessage::eNewThreadMessage:
+ case ProcessMessage::eCrashMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ break;
+ }
+
+ m_message_queue.push(message);
+}
+
+void
+ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid)
+{
+ // FIXME: Will this work the same way on FreeBSD and Linux?
+}
+
+bool
+ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
+{
+ bool added_to_set = false;
+ ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid);
+ if (it == m_seen_initial_stop.end())
+ {
+ m_seen_initial_stop.insert(stop_tid);
+ added_to_set = true;
+ }
+ return added_to_set;
+}
+
+POSIXThread *
+ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid)
+{
+ return new POSIXThread(process, tid);
+}
+
+void
+ProcessPOSIX::RefreshStateAfterStop()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size());
+
+ Mutex::Locker lock(m_message_mutex);
+
+ // This method used to only handle one message. Changing it to loop allows
+ // it to handle the case where we hit a breakpoint while handling a different
+ // breakpoint.
+ while (!m_message_queue.empty())
+ {
+ ProcessMessage &message = m_message_queue.front();
+
+ // Resolve the thread this message corresponds to and pass it along.
+ lldb::tid_t tid = message.GetTID();
+ if (log)
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid);
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ GetThreadList().FindThreadByID(tid, false).get());
+
+ if (message.GetKind() == ProcessMessage::eNewThreadMessage)
+ {
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID());
+ lldb::tid_t child_tid = message.GetChildTID();
+ ThreadSP thread_sp;
+ thread_sp.reset(CreateNewPOSIXThread(*this, child_tid));
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ m_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list.RefreshStateAfterStop();
+
+ if (thread)
+ thread->Notify(message);
+
+ if (message.GetKind() == ProcessMessage::eExitMessage)
+ {
+ // FIXME: We should tell the user about this, but the limbo message is probably better for that.
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
+ thread_sp.reset();
+ m_seen_initial_stop.erase(tid);
+ }
+
+ m_message_queue.pop();
+ }
+}
+
+bool
+ProcessPOSIX::IsAlive()
+{
+ StateType state = GetPrivateState();
+ return state != eStateDetached
+ && state != eStateExited
+ && state != eStateInvalid
+ && state != eStateUnloaded;
+}
+
+size_t
+ProcessPOSIX::DoReadMemory(addr_t vm_addr,
+ void *buf, size_t size, Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->ReadMemory(vm_addr, buf, size, error);
+}
+
+size_t
+ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
+ Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->WriteMemory(vm_addr, buf, size, error);
+}
+
+addr_t
+ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions,
+ Error &error)
+{
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
+ m_addr_to_mmap_size[allocated_addr] = size;
+ error.Clear();
+ } else {
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
+ }
+
+ return allocated_addr;
+}
+
+Error
+ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
+{
+ Error error;
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase (pos);
+ else
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+
+ return error;
+}
+
+addr_t
+ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error)
+{
+ addr_t function_addr = LLDB_INVALID_ADDRESS;
+ if (address == NULL) {
+ error.SetErrorStringWithFormat("unable to determine direct function call for NULL address");
+ } else if (!InferiorCall(this, address, function_addr)) {
+ function_addr = LLDB_INVALID_ADDRESS;
+ error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s",
+ address->CalculateSymbolContextSymbol()->GetName().AsCString());
+ }
+ return function_addr;
+}
+
+size_t
+ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
+{
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+
+ ArchSpec arch = GetTarget().GetArchitecture();
+ const uint8_t *opcode = NULL;
+ size_t opcode_size = 0;
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_64_x86_64:
+ opcode = g_i386_opcode;
+ opcode_size = sizeof(g_i386_opcode);
+ break;
+ }
+
+ bp_site->SetTrapOpcode(opcode, opcode_size);
+ return opcode_size;
+}
+
+Error
+ProcessPOSIX::EnableBreakpointSite(BreakpointSite *bp_site)
+{
+ return EnableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site)
+{
+ return DisableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+ watchID, (uint64_t)addr);
+ return error;
+ }
+
+ // Try to find a vacant watchpoint slot in the inferiors' main thread
+ uint32_t wp_hw_index = LLDB_INVALID_INDEX32;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+
+ if (thread)
+ wp_hw_index = thread->FindVacantWatchpointIndex();
+
+ if (wp_hw_index == LLDB_INVALID_INDEX32)
+ {
+ error.SetErrorString("Setting hardware watchpoint failed.");
+ }
+ else
+ {
+ wp->SetHardwareIndex(wp_hw_index);
+ bool wp_enabled = true;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_enabled &= thread->EnableHardwareWatchpoint(wp);
+ else
+ wp_enabled = false;
+ }
+ if (wp_enabled)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ {
+ // Watchpoint enabling failed on at least one
+ // of the threads so roll back all of them
+ DisableWatchpoint(wp, false);
+ error.SetErrorString("Setting hardware watchpoint failed");
+ }
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.",
+ watchID, (uint64_t)addr);
+ // This is needed (for now) to keep watchpoints disabled correctly
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ bool wp_disabled = true;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_disabled &= thread->DisableHardwareWatchpoint(wp);
+ else
+ wp_disabled = false;
+ }
+ if (wp_disabled)
+ {
+ wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("Disabling hardware watchpoint failed");
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num)
+{
+ Error error;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+ if (thread)
+ num = thread->NumSupportedHardwareWatchpoints();
+ else
+ error.SetErrorString("Process does not exist.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after)
+{
+ Error error = GetWatchpointSupportInfo(num);
+ // Watchpoints trigger and halt the inferior after
+ // the corresponding instruction has been executed.
+ after = true;
+ return error;
+}
+
+uint32_t
+ProcessPOSIX::UpdateThreadListIfNeeded()
+{
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ // Do not allow recursive updates.
+ return m_thread_list.GetSize(false);
+}
+
+bool
+ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ // Update the process thread list with this new thread.
+ // FIXME: We should be using tid, not pid.
+ assert(m_monitor);
+ ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
+ if (!thread_sp) {
+ thread_sp.reset(CreateNewPOSIXThread(*this, GetID()));
+ }
+
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID());
+ new_thread_list.AddThread(thread_sp);
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+ByteOrder
+ProcessPOSIX::GetByteOrder() const
+{
+ // FIXME: We should be able to extract this value directly. See comment in
+ // ProcessPOSIX().
+ return m_byte_order;
+}
+
+size_t
+ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error)
+{
+ ssize_t status;
+ if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0)
+ {
+ error.SetErrorToErrno();
+ return 0;
+ }
+ return status;
+}
+
+UnixSignals &
+ProcessPOSIX::GetUnixSignals()
+{
+ return m_signals;
+}
+
+//------------------------------------------------------------------------------
+// Utility functions.
+
+bool
+ProcessPOSIX::HasExited()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateDetached:
+ case eStateExited:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsStopped()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsAThreadRunning()
+{
+ bool is_running = false;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ StateType thread_state = thread->GetState();
+ if (thread_state == eStateRunning || thread_state == eStateStepping)
+ {
+ is_running = true;
+ break;
+ }
+ }
+ return is_running;
+}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h
new file mode 100644
index 000000000000..48b19bac47e7
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -0,0 +1,211 @@
+//===-- ProcessPOSIX.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_ProcessPOSIX_H_
+#define liblldb_ProcessPOSIX_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+#include <set>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/UnixSignals.h"
+#include "ProcessMessage.h"
+
+class ProcessMonitor;
+class POSIXThread;
+
+class ProcessPOSIX :
+ public lldb_private::Process
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessPOSIX(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessPOSIX();
+
+ //------------------------------------------------------------------
+ // Process protocol.
+ //------------------------------------------------------------------
+ virtual void
+ Finalize();
+
+ virtual bool
+ CanDebug(lldb_private::Target &target, bool plugin_specified_by_name);
+
+ virtual lldb_private::Error
+ WillLaunch(lldb_private::Module *module);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID(lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ const lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb_private::Error
+ DoResume();
+
+ virtual lldb_private::Error
+ DoHalt(bool &caused_stop);
+
+ virtual lldb_private::Error
+ DoDetach(bool keep_stopped);
+
+ virtual lldb_private::Error
+ DoSignal(int signal);
+
+ virtual lldb_private::Error
+ DoDestroy();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual bool
+ IsAlive();
+
+ virtual size_t
+ DoReadMemory(lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory(lldb::addr_t vm_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);
+
+ virtual lldb::addr_t
+ ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
+
+ virtual lldb_private::Error
+ EnableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num, bool &after);
+
+ virtual uint32_t
+ UpdateThreadListIfNeeded();
+
+ virtual bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) = 0;
+
+ virtual lldb::ByteOrder
+ GetByteOrder() const;
+
+ virtual lldb::addr_t
+ GetImageInfoAddress();
+
+ virtual size_t
+ PutSTDIN(const char *buf, size_t len, lldb_private::Error &error);
+
+ //--------------------------------------------------------------------------
+ // ProcessPOSIX internal API.
+
+ /// Registers the given message with this process.
+ void SendMessage(const ProcessMessage &message);
+
+ ProcessMonitor &
+ GetMonitor() { assert(m_monitor); return *m_monitor; }
+
+ lldb_private::UnixSignals &
+ GetUnixSignals();
+
+ const char *
+ GetFilePath(const lldb_private::ProcessLaunchInfo::FileAction *file_action,
+ const char *default_path);
+
+ /// Stops all threads in the process.
+ /// The \p stop_tid parameter indicates the thread which initiated the stop.
+ virtual void
+ StopAllThreads(lldb::tid_t stop_tid);
+
+ /// Adds the thread to the list of threads for which we have received the initial stopping signal.
+ /// The \p stop_tid paramter indicates the thread which the stop happened for.
+ bool
+ AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
+
+ virtual POSIXThread *
+ CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+protected:
+ /// Target byte order.
+ lldb::ByteOrder m_byte_order;
+
+ /// Process monitor;
+ ProcessMonitor *m_monitor;
+
+ /// The module we are executing.
+ lldb_private::Module *m_module;
+
+ /// Message queue notifying this instance of inferior process state changes.
+ lldb_private::Mutex m_message_mutex;
+ std::queue<ProcessMessage> m_message_queue;
+
+ /// Drive any exit events to completion.
+ bool m_exit_now;
+
+ /// OS-specific signal set.
+ lldb_private::UnixSignals m_signals;
+
+ /// Returns true if the process has exited.
+ bool HasExited();
+
+ /// Returns true if the process is stopped.
+ bool IsStopped();
+
+ /// Returns true if at least one running is currently running
+ bool IsAThreadRunning();
+
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ MMapMap m_addr_to_mmap_size;
+
+ typedef std::set<lldb::tid_t> ThreadStopSet;
+ /// Every thread begins with a stop signal. This keeps track
+ /// of the threads for which we have received the stop signal.
+ ThreadStopSet m_seen_initial_stop;
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
new file mode 100644
index 000000000000..624ca87b883a
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
@@ -0,0 +1,193 @@
+//===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessPOSIXLog.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_log_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+
+Log *
+ProcessPOSIXLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+static uint32_t
+GetFlagBits (const char *arg)
+{
+ if (::strcasecmp (arg, "all") == 0 ) return POSIX_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) return POSIX_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) return POSIX_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) return POSIX_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) return POSIX_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) return POSIX_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) return POSIX_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) return POSIX_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) return POSIX_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) return POSIX_LOG_PROCESS;
+ else if (::strcasecmp (arg, "ptrace") == 0 ) return POSIX_LOG_PTRACE;
+ else if (::strcasecmp (arg, "registers") == 0 ) return POSIX_LOG_REGISTERS;
+ else if (::strcasecmp (arg, "step") == 0 ) return POSIX_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) return POSIX_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) return POSIX_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) return POSIX_LOG_WATCHPOINTS;
+ return 0;
+}
+
+void
+ProcessPOSIXLog::DisableLog (const char **args, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ flag_bits = log->GetMask().Get();
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits &= ~bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+ }
+
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ }
+
+ return;
+}
+
+Log *
+ProcessPOSIXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **args, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits |= bits;
+ }
+ 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 = POSIX_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ g_log_enabled = true;
+ }
+ return g_log;
+}
+
+void
+ProcessPOSIXLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ " ptrace - log all calls to ptrace\n"
+#endif
+ " registers - log register read/writes\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n", ProcessPOSIXLog::m_pluginname);
+}
+
+
+void
+ProcessPOSIXLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+int ProcessPOSIXLog::m_nestinglevel;
+const char *ProcessPOSIXLog::m_pluginname = "";
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
new file mode 100644
index 000000000000..a1e2e3747d21
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
@@ -0,0 +1,111 @@
+//===-- ProcessPOSIXLog.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_ProcessPOSIXLog_h_
+#define liblldb_ProcessPOSIXLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define POSIX_LOG_VERBOSE (1u << 0)
+#define POSIX_LOG_PROCESS (1u << 1)
+#define POSIX_LOG_THREAD (1u << 2)
+#define POSIX_LOG_PACKETS (1u << 3)
+#define POSIX_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define POSIX_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define POSIX_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define POSIX_LOG_BREAKPOINTS (1u << 7)
+#define POSIX_LOG_WATCHPOINTS (1u << 8)
+#define POSIX_LOG_STEP (1u << 9)
+#define POSIX_LOG_COMM (1u << 10)
+#define POSIX_LOG_ASYNC (1u << 11)
+#define POSIX_LOG_PTRACE (1u << 12)
+#define POSIX_LOG_REGISTERS (1u << 13)
+#define POSIX_LOG_ALL (UINT32_MAX)
+#define POSIX_LOG_DEFAULT POSIX_LOG_PACKETS
+
+// The size which determines "short memory reads/writes".
+#define POSIX_LOG_MEMORY_SHORT_BYTES (4 * sizeof(ptrdiff_t))
+
+class ProcessPOSIXLog
+{
+ static int m_nestinglevel;
+ static const char *m_pluginname;
+
+public:
+ static void
+ RegisterPluginName(const char *pluginName)
+ {
+ m_pluginname = pluginName;
+ }
+
+ static void
+ RegisterPluginName(lldb_private::ConstString pluginName)
+ {
+ m_pluginname = pluginName.GetCString();
+ }
+
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog (const char **args, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options,
+ const char **args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+
+ // The following functions can be used to enable the client to limit
+ // logging to only the top level function calls. This is useful for
+ // recursive functions. FIXME: not thread safe!
+ // Example:
+ // void NestingFunc() {
+ // LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_ALL));
+ // if (log)
+ // {
+ // ProcessPOSIXLog::IncNestLevel();
+ // if (ProcessPOSIXLog::AtTopNestLevel())
+ // log->Print(msg);
+ // }
+ // NestingFunc();
+ // if (log)
+ // ProcessPOSIXLog::DecNestLevel();
+ // }
+
+ static bool
+ AtTopNestLevel()
+ {
+ return m_nestinglevel == 1;
+ }
+
+ static void
+ IncNestLevel()
+ {
+ ++m_nestinglevel;
+ }
+
+ static void
+ DecNestLevel()
+ {
+ --m_nestinglevel;
+ assert(m_nestinglevel >= 0);
+ }
+};
+
+#endif // liblldb_ProcessPOSIXLog_h_
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..0fb9dc1cb3dc
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,136 @@
+//===-- RegisterContextFreeBSD_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.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSD_x86_64.h"
+#include <vector>
+
+using namespace lldb_private;
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+
+// Update the FreeBSD specific information (offset and size).
+#define UPDATE_GPR_INFO(reg) \
+do { \
+ GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \
+ GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define UPDATE_I386_GPR_INFO(i386_reg, reg) \
+do { \
+ GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t rax;
+ uint32_t trapno;
+ uint16_t fs;
+ uint16_t gs;
+ uint32_t err;
+ uint16_t es;
+ uint16_t ds;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+} GPR;
+
+// Use a singleton function to avoid global constructors in shared libraries.
+static std::vector<RegisterInfo> & GetRegisterContext () {
+ static std::vector<RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(Thread &thread, uint32_t concrete_frame_idx):
+ RegisterContext_x86_64(thread, concrete_frame_idx)
+{
+}
+
+size_t
+RegisterContextFreeBSD_x86_64::GetGPRSize()
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_x86_64::GetRegisterInfo()
+{
+ // Allocate RegisterInfo only once
+ if (GetRegisterContext().empty())
+ {
+ // Copy the register information from base class
+ const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo();
+ if (base_info)
+ {
+ GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]);
+ // Update the FreeBSD specific register information (offset and size).
+ UpdateRegisterInfo();
+ }
+ }
+ return &GetRegisterContext()[0];
+}
+
+void
+RegisterContextFreeBSD_x86_64::UpdateRegisterInfo()
+{
+ UPDATE_GPR_INFO(rax);
+ UPDATE_GPR_INFO(rbx);
+ UPDATE_GPR_INFO(rcx);
+ UPDATE_GPR_INFO(rdx);
+ UPDATE_GPR_INFO(rdi);
+ UPDATE_GPR_INFO(rsi);
+ UPDATE_GPR_INFO(rbp);
+ UPDATE_GPR_INFO(rsp);
+ UPDATE_GPR_INFO(r8);
+ UPDATE_GPR_INFO(r9);
+ UPDATE_GPR_INFO(r10);
+ UPDATE_GPR_INFO(r11);
+ UPDATE_GPR_INFO(r12);
+ UPDATE_GPR_INFO(r13);
+ UPDATE_GPR_INFO(r14);
+ UPDATE_GPR_INFO(r15);
+ UPDATE_GPR_INFO(rip);
+ UPDATE_GPR_INFO(rflags);
+ UPDATE_GPR_INFO(cs);
+ UPDATE_GPR_INFO(fs);
+ UPDATE_GPR_INFO(gs);
+ UPDATE_GPR_INFO(ss);
+ UPDATE_GPR_INFO(ds);
+ UPDATE_GPR_INFO(es);
+
+ UPDATE_I386_GPR_INFO(eax, rax);
+ UPDATE_I386_GPR_INFO(ebx, rbx);
+ UPDATE_I386_GPR_INFO(ecx, rcx);
+ UPDATE_I386_GPR_INFO(edx, rdx);
+ UPDATE_I386_GPR_INFO(edi, rdi);
+ UPDATE_I386_GPR_INFO(esi, rsi);
+ UPDATE_I386_GPR_INFO(ebp, rbp);
+ UPDATE_I386_GPR_INFO(esp, rsp);
+ UPDATE_I386_GPR_INFO(eip, rip);
+ UPDATE_I386_GPR_INFO(eflags, rflags);
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h
new file mode 100644
index 000000000000..ffff40a9c65b
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextFreeBSD_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_RegisterContextFreeBSD_x86_64_H_
+#define liblldb_RegisterContextFreeBSD_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContext_x86_64.h"
+
+class RegisterContextFreeBSD_x86_64:
+ public RegisterContext_x86_64
+{
+public:
+ RegisterContextFreeBSD_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ size_t
+ GetGPRSize();
+
+protected:
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual void
+ UpdateRegisterInfo();
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
new file mode 100644
index 000000000000..c1aea2a41a1f
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
@@ -0,0 +1,180 @@
+//===-- RegisterContextLinux_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.
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+#include "RegisterContextLinux_x86_64.h"
+#include <vector>
+
+using namespace lldb_private;
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+
+// Update the Linux specific information (offset and size).
+#define UPDATE_GPR_INFO(reg) \
+do { \
+ GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \
+ GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define UPDATE_I386_GPR_INFO(i386_reg, reg) \
+do { \
+ GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
+
+#define UPDATE_DR_INFO(reg_index) \
+do { \
+ GetRegisterContext()[dr##reg_index].byte_size = sizeof(UserArea::u_debugreg[0]); \
+ GetRegisterContext()[dr##reg_index].byte_offset = DR_OFFSET(reg_index); \
+} while(false);
+
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t orig_ax;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+ uint64_t fs_base;
+ uint64_t gs_base;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+} GPR;
+
+typedef RegisterContext_x86_64::FXSAVE FXSAVE;
+
+struct UserArea
+{
+ GPR gpr; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ int32_t pad0;
+ FXSAVE i387; // General purpose floating point registers (see FPR for extended register sets).
+ uint64_t tsize; // Text segment size.
+ uint64_t dsize; // Data segment size.
+ uint64_t ssize; // Stack segment size.
+ uint64_t start_code; // VM address of text.
+ uint64_t start_stack; // VM address of stack bottom (top in rsp).
+ int64_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ int32_t pad1;
+ uint64_t ar0; // Location of GPR's.
+ FXSAVE* fpstate; // Location of FPR's.
+ uint64_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint64_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ uint64_t error_code; // CPU error code.
+ uint64_t fault_address; // Control register CR3.
+};
+
+// Use a singleton function to avoid global constructors in shared libraries.
+static std::vector<RegisterInfo> & GetRegisterContext () {
+ static std::vector<RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(Thread &thread, uint32_t concrete_frame_idx):
+ RegisterContext_x86_64(thread, concrete_frame_idx)
+{
+}
+
+size_t
+RegisterContextLinux_x86_64::GetGPRSize()
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextLinux_x86_64::GetRegisterInfo()
+{
+ // Allocate RegisterInfo only once
+ if (GetRegisterContext().empty())
+ {
+ // Copy the register information from base class
+ const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo();
+ if (base_info)
+ {
+ GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]);
+ // Update the Linux specific register information (offset and size).
+ UpdateRegisterInfo();
+ }
+ }
+ return &GetRegisterContext()[0];
+}
+
+void
+RegisterContextLinux_x86_64::UpdateRegisterInfo()
+{
+ UPDATE_GPR_INFO(rax);
+ UPDATE_GPR_INFO(rbx);
+ UPDATE_GPR_INFO(rcx);
+ UPDATE_GPR_INFO(rdx);
+ UPDATE_GPR_INFO(rdi);
+ UPDATE_GPR_INFO(rsi);
+ UPDATE_GPR_INFO(rbp);
+ UPDATE_GPR_INFO(rsp);
+ UPDATE_GPR_INFO(r8);
+ UPDATE_GPR_INFO(r9);
+ UPDATE_GPR_INFO(r10);
+ UPDATE_GPR_INFO(r11);
+ UPDATE_GPR_INFO(r12);
+ UPDATE_GPR_INFO(r13);
+ UPDATE_GPR_INFO(r14);
+ UPDATE_GPR_INFO(r15);
+ UPDATE_GPR_INFO(rip);
+ UPDATE_GPR_INFO(rflags);
+ UPDATE_GPR_INFO(cs);
+ UPDATE_GPR_INFO(fs);
+ UPDATE_GPR_INFO(gs);
+ UPDATE_GPR_INFO(ss);
+ UPDATE_GPR_INFO(ds);
+ UPDATE_GPR_INFO(es);
+
+ UPDATE_I386_GPR_INFO(eax, rax);
+ UPDATE_I386_GPR_INFO(ebx, rbx);
+ UPDATE_I386_GPR_INFO(ecx, rcx);
+ UPDATE_I386_GPR_INFO(edx, rdx);
+ UPDATE_I386_GPR_INFO(edi, rdi);
+ UPDATE_I386_GPR_INFO(esi, rsi);
+ UPDATE_I386_GPR_INFO(ebp, rbp);
+ UPDATE_I386_GPR_INFO(esp, rsp);
+ UPDATE_I386_GPR_INFO(eip, rip);
+ UPDATE_I386_GPR_INFO(eflags, rflags);
+
+ UPDATE_DR_INFO(0);
+ UPDATE_DR_INFO(1);
+ UPDATE_DR_INFO(2);
+ UPDATE_DR_INFO(3);
+ UPDATE_DR_INFO(4);
+ UPDATE_DR_INFO(5);
+ UPDATE_DR_INFO(6);
+ UPDATE_DR_INFO(7);
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h
new file mode 100644
index 000000000000..1509ef55b8dc
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextLinux_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_RegisterContextLinux_x86_64_H_
+#define liblldb_RegisterContextLinux_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContext_x86_64.h"
+
+class RegisterContextLinux_x86_64:
+ public RegisterContext_x86_64
+{
+public:
+ RegisterContextLinux_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ size_t
+ GetGPRSize();
+
+protected:
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual void
+ UpdateRegisterInfo();
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
new file mode 100644
index 000000000000..63ae01e83a90
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
@@ -0,0 +1,70 @@
+//===-- RegisterContextPOSIX.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_RegisterContextPOSIX_H_
+#define liblldb_RegisterContextPOSIX_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Target/RegisterContext.h"
+
+//------------------------------------------------------------------------------
+/// @class RegisterContextPOSIX
+///
+/// @brief Extends RegisterClass with a few virtual operations useful on POSIX.
+class RegisterContextPOSIX
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx)
+ { m_watchpoints_initialized = false; }
+
+ /// Updates the register state of the associated thread after hitting a
+ /// breakpoint (if that make sense for the architecture). Default
+ /// implementation simply returns true for architectures which do not
+ /// require any update.
+ ///
+ /// @return
+ /// True if the operation succeeded and false otherwise.
+ virtual bool UpdateAfterBreakpoint() { return true; }
+
+ /// Determines the index in lldb's register file given a kernel byte offset.
+ virtual unsigned
+ GetRegisterIndexFromOffset(unsigned offset) { return LLDB_INVALID_REGNUM; }
+
+ // Checks to see if a watchpoint specified by hw_index caused the inferior
+ // to stop.
+ virtual bool
+ IsWatchpointHit (uint32_t hw_index) { return false; }
+
+ // Resets any watchpoints that have been hit.
+ virtual bool
+ ClearWatchpointHits () { return false; }
+
+ // Returns the watchpoint address associated with a watchpoint hardware
+ // index.
+ virtual lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index) { return LLDB_INVALID_ADDRESS; }
+
+ virtual bool
+ IsWatchpointVacant (uint32_t hw_index) { return false; }
+
+ virtual bool
+ SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index) { return false; }
+
+protected:
+ bool m_watchpoints_initialized;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_H_
diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.cpp b/source/Plugins/Process/POSIX/RegisterContext_i386.cpp
new file mode 100644
index 000000000000..49676bd3fc73
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_i386.cpp
@@ -0,0 +1,551 @@
+//===-- RegisterContextPOSIX_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 "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+enum
+{
+ k_first_gpr,
+ gpr_eax = k_first_gpr,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+#ifdef __FreeBSD__
+ gpr_orig_ax,
+#endif
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+ k_last_gpr = gpr_gs,
+
+ k_first_fpr,
+ fpu_fcw = k_first_fpr,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_foo,
+ fpu_fos,
+ fpu_mxcsr,
+ 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,
+ k_last_fpr = fpu_xmm7,
+
+ k_num_registers,
+ k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
+ k_num_fpu_registers = k_last_fpr - k_first_fpr + 1
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+static const
+uint32_t g_gpr_regnums[k_num_gpr_registers] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+#ifdef __FreeBSD__
+ gpr_orig_ax,
+#endif
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+};
+
+static const uint32_t
+g_fpu_regnums[k_num_fpu_registers] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_foo,
+ fpu_fos,
+ fpu_mxcsr,
+ 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,
+};
+
+static const RegisterSet
+g_reg_sets[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }
+};
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(RegisterContext_i386::UserArea, regs) + \
+ offsetof(RegisterContext_i386::GPR, regname))
+
+// Computes the offset of the given FPR in the user data area.
+#define FPR_OFFSET(regname) \
+ (offsetof(RegisterContext_i386::UserArea, i387) + \
+ offsetof(RegisterContext_i386::FPU, regname))
+
+// Number of bytes needed to represent a GPR.
+#define GPR_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg)
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((RegisterContext_i386::FPU*)NULL)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((RegisterContext_i386::MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(RegisterContext_i386::XMMReg)
+
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL }
+
+#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \
+ { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL }
+
+#define DEFINE_FP(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { dwarf_##reg##i, dwarf_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { dwarf_##reg##i, dwarf_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+static RegisterInfo
+g_register_infos[k_num_registers] =
+{
+ // General purpose registers.
+ 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_INVALID_REGNUM, gdb_ebp),
+ DEFINE_GPR(esp, "sp", gcc_esp, dwarf_esp, LLDB_INVALID_REGNUM, 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_INVALID_REGNUM, gdb_eflags),
+ DEFINE_GPR(eip, "pc", gcc_eip, dwarf_eip, LLDB_INVALID_REGNUM, 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),
+
+ // Floating point registers.
+ DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fcw),
+ DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fsw),
+ DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftw),
+ DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop),
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ip),
+ DEFINE_FPR(cs, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs),
+ DEFINE_FPR(foo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_dp),
+ DEFINE_FPR(fos, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds),
+ DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_mxcsr),
+
+ DEFINE_FP(stmm, 0),
+ DEFINE_FP(stmm, 1),
+ DEFINE_FP(stmm, 2),
+ DEFINE_FP(stmm, 3),
+ DEFINE_FP(stmm, 4),
+ DEFINE_FP(stmm, 5),
+ DEFINE_FP(stmm, 6),
+ DEFINE_FP(stmm, 7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+
+};
+
+#ifndef NDEBUG
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+#endif
+
+static unsigned GetRegOffset(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return g_register_infos[reg].byte_offset;
+}
+
+static unsigned GetRegSize(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return g_register_infos[reg].byte_size;
+}
+
+RegisterContext_i386::RegisterContext_i386(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextPOSIX(thread, concrete_frame_idx)
+{
+}
+
+RegisterContext_i386::~RegisterContext_i386()
+{
+}
+
+ProcessMonitor &
+RegisterContext_i386::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+void
+RegisterContext_i386::Invalidate()
+{
+}
+
+void
+RegisterContext_i386::InvalidateAllRegisters()
+{
+}
+
+size_t
+RegisterContext_i386::GetRegisterCount()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContext_i386::GetRegisterInfoAtIndex(size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContext_i386::GetRegisterSetCount()
+{
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+RegisterContext_i386::GetRegisterSet(size_t set)
+{
+ if (set < k_num_register_sets)
+ return &g_reg_sets[set];
+ else
+ return NULL;
+}
+
+unsigned
+RegisterContext_i386::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers; reg++)
+ {
+ if (g_register_infos[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return reg;
+}
+
+const char *
+RegisterContext_i386::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return g_register_infos[reg].name;
+}
+
+bool
+RegisterContext_i386::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(), GetRegOffset(reg),
+ GetRegisterName(reg), GetRegSize(reg), value);
+}
+
+bool
+RegisterContext_i386::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool RegisterContext_i386::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(), GetRegOffset(reg),
+ GetRegisterName(reg), value);
+}
+
+bool
+RegisterContext_i386::WriteAllRegisterValues(const DataBufferSP &data)
+{
+ return false;
+}
+
+bool
+RegisterContext_i386::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+uint32_t
+RegisterContext_i386::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+ uint32_t num)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ 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:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_eip: return gpr_eip;
+ 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;
+ 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;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ 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_fcw : return fpu_fcw;
+ case gdb_fsw : return fpu_fsw;
+ case gdb_ftw : return fpu_ftw;
+ case gdb_fpu_cs : return fpu_cs;
+ case gdb_ip : return fpu_ip;
+ case gdb_fpu_ds : return fpu_fos;
+ case gdb_dp : return fpu_foo;
+ 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:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContext_i386::HardwareSingleStep(bool enable)
+{
+ enum { TRACE_BIT = 0x100 };
+ uint64_t eflags;
+
+ if ((eflags = ReadRegisterAsUnsigned(gpr_eflags, -1UL)) == -1UL)
+ return false;
+
+ if (enable)
+ {
+ if (eflags & TRACE_BIT)
+ return true;
+
+ eflags |= TRACE_BIT;
+ }
+ else
+ {
+ if (!(eflags & TRACE_BIT))
+ return false;
+
+ eflags &= ~TRACE_BIT;
+ }
+
+ return WriteRegisterFromUnsigned(gpr_eflags, eflags);
+}
+
+void
+RegisterContext_i386::LogGPR(const char *title)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+ 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.8" PRIx64, g_register_infos[reg].name, ((uint64_t*)&user.regs)[reg]);
+ }
+ }
+}
+
+bool
+RegisterContext_i386::ReadGPR()
+{
+ bool result;
+
+ ProcessMonitor &monitor = GetMonitor();
+ result = monitor.ReadGPR(m_thread.GetID(), &user.regs, sizeof(user.regs));
+ LogGPR("RegisterContext_i386::ReadGPR()");
+ return result;
+}
+
+bool
+RegisterContext_i386::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &user.i387, sizeof(user.i387));
+}
diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.h b/source/Plugins/Process/POSIX/RegisterContext_i386.h
new file mode 100644
index 000000000000..96066c47b815
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_i386.h
@@ -0,0 +1,169 @@
+//===-- RegisterContext_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_RegisterContext_i386_h_
+#define liblldb_RegisterContext_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+
+class RegisterContext_i386 : public RegisterContextPOSIX
+{
+public:
+ RegisterContext_i386(lldb_private::Thread &thread,
+ uint32_t concreate_frame_idx);
+
+ ~RegisterContext_i386();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ bool
+ ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value);
+
+ bool
+ ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value);
+
+ bool
+ WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data,
+ uint32_t data_offset = 0);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+ struct GPR
+ {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t orig_ax;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+ uint32_t esp;
+ uint32_t ss;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[8];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint16_t ftw;
+ uint16_t fop;
+ uint32_t ip;
+ uint32_t cs;
+ uint32_t foo;
+ uint32_t fos;
+ uint32_t mxcsr;
+ uint32_t reserved;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint32_t pad[56];
+ };
+
+ // A user area like this no longer exists on FreeBSD
+ // making this a Linux artifact. Nonetheless, it is safe
+ // leaving it here while the code is being cleaned up and generalized.
+
+ struct UserArea
+ {
+ GPR regs; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ FPU i387; // FPU registers.
+ uint32_t tsize; // Text segment size.
+ uint32_t dsize; // Data segment size.
+ uint32_t ssize; // Stack segment size.
+ uint32_t start_code; // VM address of text.
+ uint32_t start_stack; // VM address of stack bottom (top in rsp).
+ int32_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ uint32_t ar0; // Location of GPR's.
+ FPU* fpstate; // Location of FPR's.
+ uint32_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ };
+private:
+ UserArea user;
+
+ ProcessMonitor &GetMonitor();
+
+ void LogGPR(const char *title);
+
+ bool ReadGPR();
+ bool ReadFPR();
+};
+
+#endif // #ifndef liblldb_RegisterContext_i386_h_
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86.h b/source/Plugins/Process/POSIX/RegisterContext_x86.h
new file mode 100644
index 000000000000..61a25c407758
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86.h
@@ -0,0 +1,110 @@
+//===-- RegisterContext_x86.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_RegisterContext_x86_H_
+#define liblldb_RegisterContext_x86_H_
+
+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_fcw = 24,
+ gdb_fsw = 25,
+ gdb_ftw = 26,
+ gdb_fpu_cs = 27,
+ gdb_ip = 28,
+ gdb_fpu_ds = 29,
+ gdb_dp = 30,
+ 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
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
new file mode 100644
index 000000000000..617b18484e5a
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
@@ -0,0 +1,1563 @@
+//===-- RegisterContext_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 <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "ProcessPOSIX.h"
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "ProcessMonitor.h"
+#endif
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86.h"
+#include "RegisterContext_x86_64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+ #define NT_X86_XSTATE 0x202
+#endif
+
+enum
+{
+ 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,
+ gcc_dwarf_fpu_ymm0,
+ gcc_dwarf_fpu_ymm1,
+ gcc_dwarf_fpu_ymm2,
+ gcc_dwarf_fpu_ymm3,
+ gcc_dwarf_fpu_ymm4,
+ gcc_dwarf_fpu_ymm5,
+ gcc_dwarf_fpu_ymm6,
+ gcc_dwarf_fpu_ymm7,
+ gcc_dwarf_fpu_ymm8,
+ gcc_dwarf_fpu_ymm9,
+ gcc_dwarf_fpu_ymm10,
+ gcc_dwarf_fpu_ymm11,
+ gcc_dwarf_fpu_ymm12,
+ gcc_dwarf_fpu_ymm13,
+ gcc_dwarf_fpu_ymm14,
+ gcc_dwarf_fpu_ymm15
+};
+
+enum
+{
+ 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_fcw = 32,
+ gdb_fpu_fsw = 33,
+ gdb_fpu_ftw = 34,
+ gdb_fpu_cs_64 = 35,
+ gdb_fpu_ip = 36,
+ gdb_fpu_ds_64 = 37,
+ gdb_fpu_dp = 38,
+ 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,
+ gdb_fpu_ymm0 = 57,
+ gdb_fpu_ymm1 = 58,
+ gdb_fpu_ymm2 = 59,
+ gdb_fpu_ymm3 = 60,
+ gdb_fpu_ymm4 = 61,
+ gdb_fpu_ymm5 = 62,
+ gdb_fpu_ymm6 = 63,
+ gdb_fpu_ymm7 = 64,
+ gdb_fpu_ymm8 = 65,
+ gdb_fpu_ymm9 = 66,
+ gdb_fpu_ymm10 = 67,
+ gdb_fpu_ymm11 = 68,
+ gdb_fpu_ymm12 = 69,
+ gdb_fpu_ymm13 = 70,
+ gdb_fpu_ymm14 = 71,
+ gdb_fpu_ymm15 = 72
+};
+
+static const
+uint32_t g_gpr_regnums[k_num_gpr_registers] =
+{
+ 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,
+ gpr_ss,
+ gpr_ds,
+ gpr_es,
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_eip,
+ gpr_eflags
+};
+
+static const uint32_t
+g_fpu_regnums[k_num_fpr_registers] =
+{
+ 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 const uint32_t
+g_avx_regnums[k_num_avx_registers] =
+{
+ fpu_ymm0,
+ fpu_ymm1,
+ fpu_ymm2,
+ fpu_ymm3,
+ fpu_ymm4,
+ fpu_ymm5,
+ fpu_ymm6,
+ fpu_ymm7,
+ fpu_ymm8,
+ fpu_ymm9,
+ fpu_ymm10,
+ fpu_ymm11,
+ fpu_ymm12,
+ fpu_ymm13,
+ fpu_ymm14,
+ fpu_ymm15
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_extended_register_sets = 1,
+ k_num_register_sets = 3
+};
+
+static const RegisterSet
+g_reg_sets[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers, g_fpu_regnums },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers, g_avx_regnums }
+};
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (offsetof(RegisterContext_x86_64::FPR, xstate) + \
+ offsetof(RegisterContext_x86_64::FXSAVE, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+#define YMM_OFFSET(regname) \
+ (offsetof(RegisterContext_x86_64::YMM, regname))
+
+// Number of bytes needed to represent a i386 GPR
+#define GPR_i386_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg)
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((RegisterContext_x86_64::FXSAVE*)NULL)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((RegisterContext_x86_64::MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(RegisterContext_x86_64::XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(RegisterContext_x86_64::YMMReg)
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, 0, 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL }
+
+// Dummy data for RegisterInfo::value_regs as expected by DumpRegisterSet.
+static uint32_t value_regs = LLDB_INVALID_REGNUM;
+
+#define DEFINE_GPR_i386(reg_i386, reg_x86_64, alt, kind1, kind2, kind3, kind4) \
+ { #reg_i386, alt, GPR_i386_SIZE(reg_i386), 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg_i386 }, &value_regs, NULL }
+
+#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \
+ { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL }
+
+#define DEFINE_FP(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_YMM(reg, i) \
+ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_DR(reg, i) \
+ { #reg#i, NULL, 0, 0, eEncodingUint, eFormatHex, \
+ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+
+#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(RegisterContext_x86_64::FPR))
+
+static RegisterInfo
+g_register_infos[k_num_registers] =
+{
+ // General purpose registers.
+ 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_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ss),
+ DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ds),
+ DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_es),
+ // i386 registers
+ DEFINE_GPR_i386(eax, rax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax),
+ DEFINE_GPR_i386(ebx, rbx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx),
+ DEFINE_GPR_i386(ecx, rcx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx),
+ DEFINE_GPR_i386(edx, rdx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx),
+ DEFINE_GPR_i386(edi, rdi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi),
+ DEFINE_GPR_i386(esi, rsi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi),
+ DEFINE_GPR_i386(ebp, rbp, "fp", gcc_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, gdb_ebp),
+ DEFINE_GPR_i386(esp, rsp, "sp", gcc_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, gdb_esp),
+ DEFINE_GPR_i386(eip, rip, "pc", gcc_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, gdb_eip),
+ DEFINE_GPR_i386(eflags, rflags, "flags", gcc_eflags, dwarf_eflags, LLDB_REGNUM_GENERIC_FLAGS, gdb_eflags),
+ // i387 Floating point registers.
+ DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fcw),
+ DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fsw),
+ DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ftw),
+ DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fop),
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ip),
+ // FIXME: Extract segment from ip.
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs_64),
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_dp),
+ // FIXME: Extract segment from dp.
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds_64),
+ DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_mxcsr),
+ DEFINE_FPR(mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ // FP registers.
+ DEFINE_FP(stmm, 0),
+ DEFINE_FP(stmm, 1),
+ DEFINE_FP(stmm, 2),
+ DEFINE_FP(stmm, 3),
+ DEFINE_FP(stmm, 4),
+ DEFINE_FP(stmm, 5),
+ DEFINE_FP(stmm, 6),
+ DEFINE_FP(stmm, 7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+ DEFINE_XMM(xmm, 8),
+ DEFINE_XMM(xmm, 9),
+ DEFINE_XMM(xmm, 10),
+ DEFINE_XMM(xmm, 11),
+ DEFINE_XMM(xmm, 12),
+ DEFINE_XMM(xmm, 13),
+ DEFINE_XMM(xmm, 14),
+ DEFINE_XMM(xmm, 15),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0),
+ DEFINE_YMM(ymm, 1),
+ DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3),
+ DEFINE_YMM(ymm, 4),
+ DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6),
+ DEFINE_YMM(ymm, 7),
+ DEFINE_YMM(ymm, 8),
+ DEFINE_YMM(ymm, 9),
+ DEFINE_YMM(ymm, 10),
+ DEFINE_YMM(ymm, 11),
+ DEFINE_YMM(ymm, 12),
+ DEFINE_YMM(ymm, 13),
+ DEFINE_YMM(ymm, 14),
+ DEFINE_YMM(ymm, 15),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0),
+ DEFINE_DR(dr, 1),
+ DEFINE_DR(dr, 2),
+ DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4),
+ DEFINE_DR(dr, 5),
+ DEFINE_DR(dr, 6),
+ DEFINE_DR(dr, 7)
+};
+
+static bool IsGPR(unsigned reg)
+{
+ return reg <= k_last_gpr; // GPR's come first.
+}
+
+static bool IsAVX(unsigned reg)
+{
+ return (k_first_avx <= reg && reg <= k_last_avx);
+}
+static bool IsFPR(unsigned reg)
+{
+ return (k_first_fpr <= reg && reg <= k_last_fpr);
+}
+
+
+bool RegisterContext_x86_64::IsFPR(unsigned reg, FPRType fpr_type)
+{
+ bool generic_fpr = ::IsFPR(reg);
+ if (fpr_type == eXSAVE)
+ return generic_fpr || IsAVX(reg);
+
+ return generic_fpr;
+}
+
+RegisterContext_x86_64::RegisterContext_x86_64(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextPOSIX(thread, concrete_frame_idx)
+{
+ // Initialize m_iovec to point to the buffer and buffer size
+ // using the conventions of Berkeley style UIO structures, as required
+ // by PTRACE extensions.
+ m_iovec.iov_base = &m_fpr.xstate.xsave;
+ m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
+
+ ::memset(&m_fpr, 0, sizeof(RegisterContext_x86_64::FPR));
+
+ // elf-core yet to support ReadFPR()
+ ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+
+ // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx
+ m_fpr_type = eXSAVE; // extended floating-point registers, if available
+ if (false == ReadFPR())
+ m_fpr_type = eFXSAVE; // assume generic floating-point registers
+}
+
+RegisterContext_x86_64::~RegisterContext_x86_64()
+{
+}
+
+void
+RegisterContext_x86_64::Invalidate()
+{
+}
+
+void
+RegisterContext_x86_64::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterSize(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContext_x86_64::GetRegisterCount()
+{
+ size_t num_registers = k_num_gpr_registers + k_num_fpr_registers;
+ if (m_fpr_type == eXSAVE)
+ return num_registers + k_num_avx_registers;
+ return num_registers;
+}
+
+const RegisterInfo *
+RegisterContext_x86_64::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return g_register_infos;
+}
+
+const RegisterInfo *
+RegisterContext_x86_64::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < k_num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContext_x86_64::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+
+ return sets;
+}
+
+const RegisterSet *
+RegisterContext_x86_64::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets[set];
+ else
+ return NULL;
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return reg;
+}
+
+const char *
+RegisterContext_x86_64::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContext_x86_64::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = eByteOrderInvalid;
+ Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+// Parse ymm registers and into xmm.bytes and ymmh.bytes.
+bool RegisterContext_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+
+ if (byte_order == eByteOrderBig) {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+// Concatenate xmm.bytes with ymmh.bytes
+bool RegisterContext_x86_64::CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ if (byte_order == eByteOrderBig) {
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+bool
+RegisterContext_x86_64::IsRegisterSetAvailable(size_t set_index)
+{
+ // Note: Extended register sets are assumed to be at the end of g_reg_sets...
+ size_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+ if (m_fpr_type == eXSAVE) // ...and to start with AVX registers.
+ ++num_sets;
+
+ return (set_index < num_sets);
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg, m_fpr_type)) {
+ if (!ReadFPR())
+ return false;
+ }
+ else {
+ bool success = ReadRegister(reg, value);
+
+ // If an i386 register should be parsed from an x86_64 register...
+ if (success && reg >= k_first_i386 && reg <= k_last_i386)
+ if (value.GetByteSize() > reg_info->byte_size)
+ value.SetType(reg_info); // ...use the type specified by reg_info rather than the uint64_t default
+ return success;
+ }
+
+ if (reg_info->encoding == eEncodingVector) {
+ ByteOrder byte_order = GetByteOrder();
+
+ if (byte_order != ByteOrder::eByteOrderInvalid) {
+ if (reg >= fpu_stmm0 && reg <= fpu_stmm7) {
+ value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, byte_order);
+ }
+ if (reg >= fpu_xmm0 && reg <= fpu_xmm15) {
+ value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, byte_order);
+ }
+ if (reg >= fpu_ymm0 && reg <= fpu_ymm15) {
+ // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
+ if (m_fpr_type == eXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+ value.SetBytes(m_ymm_set.ymm[reg - fpu_ymm0].bytes, reg_info->byte_size, byte_order);
+ else
+ return false;
+ }
+ return value.GetType() == RegisterValue::eTypeBytes;
+ }
+ return false;
+ }
+
+ // Note that lldb uses slightly different naming conventions from sys/user.h
+ switch (reg)
+ {
+ default:
+ return false;
+ case fpu_dp:
+ value = m_fpr.xstate.fxsave.dp;
+ break;
+ case fpu_fcw:
+ value = m_fpr.xstate.fxsave.fcw;
+ break;
+ case fpu_fsw:
+ value = m_fpr.xstate.fxsave.fsw;
+ break;
+ case fpu_ip:
+ value = m_fpr.xstate.fxsave.ip;
+ break;
+ case fpu_fop:
+ value = m_fpr.xstate.fxsave.fop;
+ break;
+ case fpu_ftw:
+ value = m_fpr.xstate.fxsave.ftw;
+ break;
+ case fpu_mxcsr:
+ value = m_fpr.xstate.fxsave.mxcsr;
+ break;
+ case fpu_mxcsrmask:
+ value = m_fpr.xstate.fxsave.mxcsrmask;
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterContext_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success) {
+ ::memcpy (dst, &m_gpr, GetGPRSize());
+ dst += GetGPRSize();
+ }
+ if (m_fpr_type == eFXSAVE)
+ ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE) {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Assemble the YMM register content from the register halves.
+ for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg)
+ success = CopyXSTATEtoYMM(reg, byte_order);
+
+ if (success) {
+ // Copy the extended register state including the assembled ymm registers.
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+ }
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ if (IsGPR(reg)) {
+ return WriteRegister(reg, value);
+ }
+
+ if (IsFPR(reg, m_fpr_type)) {
+ switch (reg)
+ {
+ default:
+ if (reg_info->encoding != eEncodingVector)
+ return false;
+
+ if (reg >= fpu_stmm0 && reg <= fpu_stmm7)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= fpu_xmm0 && reg <= fpu_xmm15)
+ ::memcpy (m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= fpu_ymm0 && reg <= fpu_ymm15) {
+ if (m_fpr_type != eXSAVE)
+ return false; // the target processor does not support AVX
+
+ // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
+ ::memcpy (m_ymm_set.ymm[reg - fpu_ymm0].bytes, value.GetBytes(), value.GetByteSize());
+ if (false == CopyYMMtoXSTATE(reg, GetByteOrder()))
+ return false;
+ }
+ break;
+ case fpu_dp:
+ m_fpr.xstate.fxsave.dp = value.GetAsUInt64();
+ break;
+ case fpu_fcw:
+ m_fpr.xstate.fxsave.fcw = value.GetAsUInt16();
+ break;
+ case fpu_fsw:
+ m_fpr.xstate.fxsave.fsw = value.GetAsUInt16();
+ break;
+ case fpu_ip:
+ m_fpr.xstate.fxsave.ip = value.GetAsUInt64();
+ break;
+ case fpu_fop:
+ m_fpr.xstate.fxsave.fop = value.GetAsUInt16();
+ break;
+ case fpu_ftw:
+ m_fpr.xstate.fxsave.ftw = value.GetAsUInt16();
+ break;
+ case fpu_mxcsr:
+ m_fpr.xstate.fxsave.mxcsr = value.GetAsUInt32();
+ break;
+ case fpu_mxcsrmask:
+ m_fpr.xstate.fxsave.mxcsrmask = value.GetAsUInt32();
+ break;
+ }
+ if (WriteFPR()) {
+ if (IsAVX(reg))
+ return CopyYMMtoXSTATE(reg, GetByteOrder());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src) {
+ ::memcpy (&m_gpr, src, GetGPRSize());
+
+ if (WriteGPR()) {
+ src += GetGPRSize();
+ if (m_fpr_type == eFXSAVE)
+ ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
+ if (m_fpr_type == eXSAVE)
+ ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
+
+ success = WriteFPR();
+ if (success) {
+ success = true;
+
+ if (m_fpr_type == eXSAVE) {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Parse the YMM register content from the register halves.
+ for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg)
+ success = CopyYMMtoXSTATE(reg, byte_order);
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContext_x86_64::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+uint32_t
+RegisterContext_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+ uint32_t num)
+{
+ const Process *process = CalculateProcess().get();
+ if (process)
+ {
+ const ArchSpec arch = process->GetTarget().GetArchitecture();;
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ {
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ 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:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_eip: return gpr_eip;
+ 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;
+ 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;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ 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_fcw : return fpu_fcw;
+ case gdb_fsw : return fpu_fsw;
+ case gdb_ftw : return fpu_ftw;
+ case gdb_fpu_cs : return fpu_cs;
+ case gdb_ip : return fpu_ip;
+ case gdb_fpu_ds : return fpu_ds; //fpu_fos
+ case gdb_dp : return fpu_dp; //fpu_foo
+ 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:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+
+ break;
+ }
+
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ 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:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ 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;
+ case gcc_dwarf_fpu_ymm0: return fpu_ymm0;
+ case gcc_dwarf_fpu_ymm1: return fpu_ymm1;
+ case gcc_dwarf_fpu_ymm2: return fpu_ymm2;
+ case gcc_dwarf_fpu_ymm3: return fpu_ymm3;
+ case gcc_dwarf_fpu_ymm4: return fpu_ymm4;
+ case gcc_dwarf_fpu_ymm5: return fpu_ymm5;
+ case gcc_dwarf_fpu_ymm6: return fpu_ymm6;
+ case gcc_dwarf_fpu_ymm7: return fpu_ymm7;
+ case gcc_dwarf_fpu_ymm8: return fpu_ymm8;
+ case gcc_dwarf_fpu_ymm9: return fpu_ymm9;
+ case gcc_dwarf_fpu_ymm10: return fpu_ymm10;
+ case gcc_dwarf_fpu_ymm11: return fpu_ymm11;
+ case gcc_dwarf_fpu_ymm12: return fpu_ymm12;
+ case gcc_dwarf_fpu_ymm13: return fpu_ymm13;
+ case gcc_dwarf_fpu_ymm14: return fpu_ymm14;
+ case gcc_dwarf_fpu_ymm15: return fpu_ymm15;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ 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_ss;
+ case gdb_gpr_ds : return gpr_ds;
+ case gdb_gpr_es : return gpr_es;
+ 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_fcw : return fpu_fcw;
+ case gdb_fpu_fsw : return fpu_fsw;
+ case gdb_fpu_ftw : return fpu_ftw;
+ case gdb_fpu_cs_64 : return fpu_cs;
+ case gdb_fpu_ip : return fpu_ip;
+ case gdb_fpu_ds_64 : return fpu_ds;
+ case gdb_fpu_dp : return fpu_dp;
+ 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;
+ case gdb_fpu_ymm0 : return fpu_ymm0;
+ case gdb_fpu_ymm1 : return fpu_ymm1;
+ case gdb_fpu_ymm2 : return fpu_ymm2;
+ case gdb_fpu_ymm3 : return fpu_ymm3;
+ case gdb_fpu_ymm4 : return fpu_ymm4;
+ case gdb_fpu_ymm5 : return fpu_ymm5;
+ case gdb_fpu_ymm6 : return fpu_ymm6;
+ case gdb_fpu_ymm7 : return fpu_ymm7;
+ case gdb_fpu_ymm8 : return fpu_ymm8;
+ case gdb_fpu_ymm9 : return fpu_ymm9;
+ case gdb_fpu_ymm10 : return fpu_ymm10;
+ case gdb_fpu_ymm11 : return fpu_ymm11;
+ case gdb_fpu_ymm12 : return fpu_ymm12;
+ case gdb_fpu_ymm13 : return fpu_ymm13;
+ case gdb_fpu_ymm14 : return fpu_ymm14;
+ case gdb_fpu_ymm15 : return fpu_ymm15;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+ }
+ }
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+uint32_t
+RegisterContext_x86_64::NumSupportedHardwareWatchpoints()
+{
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointVacant(uint32_t hw_index)
+{
+ bool is_vacant = false;
+ RegisterValue value;
+
+ assert(hw_index < NumSupportedHardwareWatchpoints());
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (ReadRegister(dr7, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_vacant = (val & (3 << 2*hw_index)) == 0;
+ }
+
+ return is_vacant;
+}
+
+static uint32_t
+size_and_rw_bits(size_t size, bool read, bool write)
+{
+ uint32_t rw;
+ if (read) {
+ rw = 0x3; // READ or READ/WRITE
+ } else if (write) {
+ rw = 0x1; // WRITE
+ } else {
+ assert(0 && "read and write cannot both be false");
+ }
+
+ switch (size) {
+ case 1:
+ return rw;
+ case 2:
+ return (0x1 << 2) | rw;
+ case 4:
+ return (0x3 << 2) | rw;
+ case 8:
+ return (0x2 << 2) | rw;
+ default:
+ assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
+ }
+}
+
+uint32_t
+RegisterContext_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints)
+ return false;
+
+ if (!(size == 1 || size == 2 || size == 4 || size == 8))
+ return false;
+
+ if (read == false && write == false)
+ return false;
+
+ if (!IsWatchpointVacant(hw_index))
+ return false;
+
+ // Set both dr7 (debug control register) and dri (debug address register).
+
+ // dr7{7-0} encodes the local/gloabl enable bits:
+ // global enable --. .-- local enable
+ // | |
+ // v v
+ // dr0 -> bits{1-0}
+ // dr1 -> bits{3-2}
+ // dr2 -> bits{5-4}
+ // dr3 -> bits{7-6}
+ //
+ // dr7{31-16} encodes the rw/len bits:
+ // b_x+3, b_x+2, b_x+1, b_x
+ // where bits{x+1, x} => rw
+ // 0b00: execute, 0b01: write, 0b11: read-or-write,
+ // 0b10: io read-or-write (unused)
+ // and bits{x+3, x+2} => len
+ // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
+ //
+ // dr0 -> bits{19-16}
+ // dr1 -> bits{23-20}
+ // dr2 -> bits{27-24}
+ // dr3 -> bits{31-28}
+ if (hw_index < num_hw_watchpoints)
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() |
+ (1 << (2*hw_index) |
+ size_and_rw_bits(size, read, write) <<
+ (16+4*hw_index));
+
+ if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) &&
+ WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index));
+
+ if (WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointHit(uint32_t hw_index)
+{
+ bool is_hit = false;
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr6, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_hit = val & (1 << hw_index);
+ }
+ }
+
+ return is_hit;
+}
+
+addr_t
+RegisterContext_x86_64::GetWatchpointAddress(uint32_t hw_index)
+{
+ addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS;
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ if (!IsWatchpointVacant(hw_index))
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr0 + hw_index, value))
+ wp_monitor_addr = value.GetAsUInt64();
+ }
+ }
+
+ return wp_monitor_addr;
+}
+
+
+bool
+RegisterContext_x86_64::ClearWatchpointHits()
+{
+ return WriteRegister(dr6, RegisterValue((uint64_t)0));
+}
+
+bool
+RegisterContext_x86_64::HardwareSingleStep(bool enable)
+{
+ enum { TRACE_BIT = 0x100 };
+ uint64_t rflags;
+
+ if ((rflags = ReadRegisterAsUnsigned(gpr_rflags, -1UL)) == -1UL)
+ return false;
+
+ if (enable)
+ {
+ if (rflags & TRACE_BIT)
+ return true;
+
+ rflags |= TRACE_BIT;
+ }
+ else
+ {
+ if (!(rflags & TRACE_BIT))
+ return false;
+
+ rflags &= ~TRACE_BIT;
+ }
+
+ return WriteRegisterFromUnsigned(gpr_rflags, rflags);
+}
+
+#if defined(__linux__) or defined(__FreeBSD__)
+
+ProcessMonitor &
+RegisterContext_x86_64::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContext_x86_64::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr, GetGPRSize());
+}
+
+bool
+RegisterContext_x86_64::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (m_fpr_type == eFXSAVE)
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE)
+ return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr, GetGPRSize());
+}
+
+bool
+RegisterContext_x86_64::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (m_fpr_type == eFXSAVE)
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE)
+ return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ value);
+}
+
+#else
+
+bool
+RegisterContext_x86_64::ReadGPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadFPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteGPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteFPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.h b/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
new file mode 100644
index 000000000000..9d59bd78e547
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
@@ -0,0 +1,347 @@
+//===-- RegisterContext_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_RegisterContext_x86_64_H_
+#define liblldb_RegisterContext_x86_64_H_
+
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMonitor;
+
+// Internal codes for all x86_64 registers.
+enum
+{
+ k_first_gpr,
+ gpr_rax = k_first_gpr,
+ 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,
+ gpr_ss,
+ gpr_ds,
+ gpr_es,
+ k_first_i386,
+ gpr_eax = k_first_i386,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_eip,
+ gpr_eflags, // eRegisterKindLLDB == 33
+ k_last_i386 = gpr_eflags,
+ k_last_gpr = gpr_eflags,
+
+ k_first_fpr,
+ fpu_fcw = k_first_fpr,
+ 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,
+ k_last_fpr = fpu_xmm15,
+ k_first_avx,
+ fpu_ymm0 = k_first_avx,
+ fpu_ymm1,
+ fpu_ymm2,
+ fpu_ymm3,
+ fpu_ymm4,
+ fpu_ymm5,
+ fpu_ymm6,
+ fpu_ymm7,
+ fpu_ymm8,
+ fpu_ymm9,
+ fpu_ymm10,
+ fpu_ymm11,
+ fpu_ymm12,
+ fpu_ymm13,
+ fpu_ymm14,
+ fpu_ymm15,
+ k_last_avx = fpu_ymm15,
+
+ dr0,
+ dr1,
+ dr2,
+ dr3,
+ dr4,
+ dr5,
+ dr6,
+ dr7,
+
+ k_num_registers,
+ k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
+ k_num_fpr_registers = k_last_fpr - k_first_fpr + 1,
+ k_num_avx_registers = k_last_avx - k_first_avx + 1
+};
+
+class RegisterContext_x86_64
+ : public RegisterContextPOSIX
+{
+public:
+ RegisterContext_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContext_x86_64();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize() = 0;
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t, size_t size, bool read,
+ bool write, uint32_t hw_index);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ IsWatchpointHit (uint32_t hw_index);
+
+ lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ //---------------------------------------------------------------------------
+ // Generic floating-point registers
+ //---------------------------------------------------------------------------
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16]; // 128-bits for each XMM register
+ };
+
+ struct FXSAVE
+ {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint16_t ftw;
+ uint16_t fop;
+ uint64_t ip;
+ uint64_t dp;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint32_t padding[24];
+ };
+
+ //---------------------------------------------------------------------------
+ // Extended floating-point registers
+ //---------------------------------------------------------------------------
+ struct YMMHReg
+ {
+ uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register
+ };
+
+ struct YMMReg
+ {
+ uint8_t bytes[32]; // 16 * 16 bits for each YMM register
+ };
+
+ struct YMM
+ {
+ YMMReg ymm[16]; // assembled from ymmh and xmm registers
+ };
+
+ struct XSAVE_HDR
+ {
+ uint64_t xstate_bv; // OS enabled xstate mask to determine the extended states supported by the processor
+ uint64_t reserved1[2];
+ uint64_t reserved2[5];
+ } __attribute__((packed));
+
+ // x86 extensions to FXSAVE (i.e. for AVX processors)
+ struct XSAVE
+ {
+ FXSAVE i387; // floating point registers typical in i387_fxsave_struct
+ XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the following extensions are usable
+ YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE)
+ // Slot any extensions to the register file here
+ } __attribute__((packed, aligned (64)));
+
+ struct IOVEC
+ {
+ void *iov_base; // pointer to XSAVE
+ size_t iov_len; // sizeof(XSAVE)
+ };
+
+ //---------------------------------------------------------------------------
+ // Note: prefer kernel definitions over user-land
+ //---------------------------------------------------------------------------
+ enum FPRType
+ {
+ eNotValid = 0,
+ eFSAVE, // TODO
+ eFXSAVE,
+ eSOFT, // TODO
+ eXSAVE
+ };
+
+ // Floating-point registers
+ struct FPR
+ {
+ // Thread state for the floating-point unit of the processor read by ptrace.
+ union XSTATE {
+ FXSAVE fxsave; // Generic floating-point registers.
+ XSAVE xsave; // x86 extended processor state.
+ } xstate;
+ };
+
+protected:
+ // Determines if an extended register set is supported on the processor running the inferior process.
+ virtual bool
+ IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+private:
+ uint64_t m_gpr[k_num_gpr_registers]; // general purpose registers.
+ FPRType m_fpr_type; // determines the type of data stored by union FPR, if any.
+ FPR m_fpr; // floating-point registers including extended register sets.
+ IOVEC m_iovec; // wrapper for xsave.
+ YMM m_ymm_set; // copy of ymmh and xmm register halves.
+
+ ProcessMonitor &GetMonitor();
+ lldb::ByteOrder GetByteOrder();
+
+ bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order);
+ bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+ bool IsFPR(unsigned reg, FPRType fpr_type);
+
+ bool ReadGPR();
+ bool ReadFPR();
+
+ bool WriteGPR();
+ bool WriteFPR();
+};
+
+#endif // #ifndef liblldb_RegisterContext_x86_64_H_
diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h
new file mode 100644
index 000000000000..4b1f06a2f9cd
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMDefines.h
@@ -0,0 +1,110 @@
+//===-- lldb_ARMDefines.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_ARMDefines_h_
+#define lldb_ARMDefines_h_
+
+// Common defintions for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+// ARM shifter types
+typedef enum
+{
+ SRType_LSL,
+ SRType_LSR,
+ SRType_ASR,
+ SRType_ROR,
+ SRType_RRX,
+ SRType_Invalid
+} ARM_ShifterType;
+
+// ARM conditions // Meaning (integer) Meaning (floating-point) Condition flags
+#define COND_EQ 0x0 // Equal Equal Z == 1
+#define COND_NE 0x1 // Not equal Not equal, or unordered Z == 0
+#define COND_CS 0x2 // Carry set >, ==, or unordered C == 1
+#define COND_HS 0x2
+#define COND_CC 0x3 // Carry clear Less than C == 0
+#define COND_LO 0x3
+#define COND_MI 0x4 // Minus, negative Less than N == 1
+#define COND_PL 0x5 // Plus, positive or zero >, ==, or unordered N == 0
+#define COND_VS 0x6 // Overflow Unordered V == 1
+#define COND_VC 0x7 // No overflow Not unordered V == 0
+#define COND_HI 0x8 // Unsigned higher Greater than, or unordered C == 1 and Z == 0
+#define COND_LS 0x9 // Unsigned lower or same Less than or equal C == 0 or Z == 1
+#define COND_GE 0xA // Greater than or equal Greater than or equal N == V
+#define COND_LT 0xB // Less than Less than, or unordered N != V
+#define COND_GT 0xC // Greater than Greater than Z == 0 and N == V
+#define COND_LE 0xD // Less than or equal <, ==, or unordered Z == 1 or N != V
+#define COND_AL 0xE // Always (unconditional) Always (unconditional) Any
+#define COND_UNCOND 0xF
+
+static inline const char *ARMCondCodeToString(uint32_t CC)
+{
+ switch (CC) {
+ default: assert(0 && "Unknown condition code");
+ case COND_EQ: return "eq";
+ case COND_NE: return "ne";
+ case COND_HS: return "hs";
+ case COND_LO: return "lo";
+ case COND_MI: return "mi";
+ case COND_PL: return "pl";
+ case COND_VS: return "vs";
+ case COND_VC: return "vc";
+ case COND_HI: return "hi";
+ case COND_LS: return "ls";
+ case COND_GE: return "ge";
+ case COND_LT: return "lt";
+ case COND_GT: return "gt";
+ case COND_LE: return "le";
+ case COND_AL: return "al";
+ }
+}
+
+// Bit positions for CPSR
+#define CPSR_T_POS 5
+#define CPSR_F_POS 6
+#define CPSR_I_POS 7
+#define CPSR_A_POS 8
+#define CPSR_E_POS 9
+#define CPSR_J_POS 24
+#define CPSR_Q_POS 27
+#define CPSR_V_POS 28
+#define CPSR_C_POS 29
+#define CPSR_Z_POS 30
+#define CPSR_N_POS 31
+
+// CPSR mode definitions
+#define CPSR_MODE_USR 0x10u
+#define CPSR_MODE_FIQ 0x11u
+#define CPSR_MODE_IRQ 0x12u
+#define CPSR_MODE_SVC 0x13u
+#define CPSR_MODE_ABT 0x17u
+#define CPSR_MODE_UND 0x1bu
+#define CPSR_MODE_SYS 0x1fu
+
+// Masks for CPSR
+#define MASK_CPSR_MODE_MASK (0x0000001fu)
+#define MASK_CPSR_IT_MASK (0x0600fc00u)
+#define MASK_CPSR_T (1u << CPSR_T_POS)
+#define MASK_CPSR_F (1u << CPSR_F_POS)
+#define MASK_CPSR_I (1u << CPSR_I_POS)
+#define MASK_CPSR_A (1u << CPSR_A_POS)
+#define MASK_CPSR_E (1u << CPSR_E_POS)
+#define MASK_CPSR_GE_MASK (0x000f0000u)
+#define MASK_CPSR_J (1u << CPSR_J_POS)
+#define MASK_CPSR_Q (1u << CPSR_Q_POS)
+#define MASK_CPSR_V (1u << CPSR_V_POS)
+#define MASK_CPSR_C (1u << CPSR_C_POS)
+#define MASK_CPSR_Z (1u << CPSR_Z_POS)
+#define MASK_CPSR_N (1u << CPSR_N_POS)
+
+} // namespace lldb_private
+
+#endif // lldb_ARMDefines_h_
diff --git a/source/Plugins/Process/Utility/ARMUtils.h b/source/Plugins/Process/Utility/ARMUtils.h
new file mode 100644
index 000000000000..76d64e15a53e
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMUtils.h
@@ -0,0 +1,394 @@
+//===-- ARMUtils.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_ARMUtils_h_
+#define lldb_ARMUtils_h_
+
+#include "ARMDefines.h"
+#include "InstructionUtils.h"
+#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
+
+// Common utilities for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+static inline uint32_t Align(uint32_t val, uint32_t alignment)
+{
+ return alignment * (val / alignment);
+}
+
+static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
+{
+ switch (type)
+ {
+ default:
+ //assert(0 && "Invalid shift type");
+ case 0:
+ shift_t = SRType_LSL;
+ return imm5;
+ case 1:
+ shift_t = SRType_LSR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 2:
+ shift_t = SRType_ASR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 3:
+ if (imm5 == 0)
+ {
+ shift_t = SRType_RRX;
+ return 1;
+ }
+ else
+ {
+ shift_t = SRType_ROR;
+ return imm5;
+ }
+ }
+ shift_t = SRType_Invalid;
+ return UINT32_MAX;
+
+}
+
+// A8.6.35 CMP (register) -- Encoding T3
+// Convenience function.
+static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12)<<2 | Bits32(opcode, 7, 6), shift_t);
+}
+
+// A8.6.35 CMP (register) -- Encoding A1
+// Convenience function.
+static inline uint32_t DecodeImmShiftARM(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
+}
+
+static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
+{
+ ARM_ShifterType dont_care;
+ return DecodeImmShift(shift_t, imm5, dont_care);
+}
+
+static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
+{
+ switch (type) {
+ default:
+ //assert(0 && "Invalid shift type");
+ return SRType_Invalid;
+ case 0:
+ return SRType_LSL;
+ case 1:
+ return SRType_LSR;
+ case 2:
+ return SRType_ASR;
+ case 3:
+ return SRType_ROR;
+ }
+}
+
+static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
+ return value << amount;
+}
+
+static inline uint32_t LSL(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSL_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
+ return value >> amount;
+}
+
+static inline uint32_t LSR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0 || amount > 32) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ bool negative = BitIsSet(value, 31);
+ if (amount <= 32)
+ {
+ carry_out = Bit32(value, amount - 1);
+ int64_t extended = llvm::SignExtend64<32>(value);
+ return UnsignedBits(extended, amount + 31, amount);
+ }
+ else
+ {
+ carry_out = (negative ? 1 : 0);
+ return (negative ? 0xffffffff : 0);
+ }
+}
+
+static inline uint32_t ASR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ASR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ uint32_t amt = amount % 32;
+ uint32_t result = Rotr32(value, amt);
+ carry_out = Bit32(value, 31);
+ return result;
+}
+
+static inline uint32_t ROR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ROR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ *success = true;
+ carry_out = Bit32(value, 0);
+ return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
+}
+
+static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in, bool *success)
+{
+ *success = true;
+ uint32_t dont_care;
+ uint32_t result = RRX_C(value, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ if (type == SRType_RRX && amount != 1) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+
+ if (amount == 0) {
+ carry_out = carry_in;
+ return value;
+ }
+ uint32_t result;
+ switch (type) {
+ case SRType_LSL:
+ result = LSL_C(value, amount, carry_out, success);
+ break;
+ case SRType_LSR:
+ result = LSR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ASR:
+ result = ASR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ROR:
+ result = ROR_C(value, amount, carry_out, success);
+ break;
+ case SRType_RRX:
+ result = RRX_C(value, carry_in, carry_out, success);
+ break;
+ default:
+ *success = false;
+ break;
+ }
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, bool *success)
+{
+ // Don't care about carry out in this case.
+ uint32_t dont_care;
+ uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
+{
+ return Bits32(val, msbit, lsbit);
+}
+
+static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
+{
+ return bits(val, msbit, msbit);
+}
+
+static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
+{
+ uint32_t m = shift % N;
+ return (val >> m) | (val << (N - m));
+}
+
+// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
+static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expanded result
+ uint32_t imm = bits(opcode, 7, 0); // immediate value
+ uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
+ if (amt == 0)
+ {
+ imm32 = imm;
+ carry_out = carry_in;
+ }
+ else
+ {
+ imm32 = ror(imm, 32, amt);
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ARMExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ARMExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
+static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expaned result
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t abcdefgh = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
+
+ if (bits(imm12, 11, 10) == 0)
+ {
+ switch (bits(imm12, 9, 8)) {
+ default: // Keep static analyzer happy with a default case
+ case 0:
+ imm32 = abcdefgh;
+ break;
+
+ case 1:
+ imm32 = abcdefgh << 16 | abcdefgh;
+ break;
+
+ case 2:
+ imm32 = abcdefgh << 24 | abcdefgh << 8;
+ break;
+
+ case 3:
+ imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
+ break;
+ }
+ carry_out = carry_in;
+ }
+ else
+ {
+ const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
+ imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ThumbExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ThumbExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// imm32 = ZeroExtend(i:imm3:imm8, 32)
+static inline uint32_t ThumbImm12(uint32_t opcode)
+{
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
+ return imm12;
+}
+
+// imm32 = ZeroExtend(imm7:'00', 32)
+static inline uint32_t ThumbImm7Scaled(uint32_t opcode)
+{
+ const uint32_t imm7 = bits(opcode, 6, 0);
+ return imm7 * 4;
+}
+
+// imm32 = ZeroExtend(imm8:'00', 32)
+static inline uint32_t ThumbImm8Scaled(uint32_t opcode)
+{
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ return imm8 * 4;
+}
+
+// This function performs the check for the register numbers 13 and 15 that are
+// not permitted for many Thumb register specifiers.
+static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
+
+} // namespace lldb_private
+
+#endif // lldb_ARMUtils_h_
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
new file mode 100644
index 000000000000..0c95d66cef94
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -0,0 +1,279 @@
+//===-- DynamicRegisterInfo.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/lldb-python.h"
+
+#include "DynamicRegisterInfo.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+
+#ifndef LLDB_DISABLE_PYTHON
+#include "lldb/Interpreter/PythonDataObjects.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+DynamicRegisterInfo::DynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+}
+
+DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict) :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+ SetRegisterInfo (dict);
+}
+
+DynamicRegisterInfo::~DynamicRegisterInfo ()
+{
+}
+
+
+size_t
+DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ PythonList sets (dict.GetItemForKey("sets"));
+ if (sets)
+ {
+ const uint32_t num_sets = sets.GetSize();
+ for (uint32_t i=0; i<num_sets; ++i)
+ {
+ PythonString py_set_name(sets.GetItemAtIndex(i));
+ ConstString set_name;
+ if (py_set_name)
+ set_name.SetCString(py_set_name.GetString());
+ if (set_name)
+ {
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ m_set_reg_nums.resize(m_sets.size());
+ }
+ PythonList regs (dict.GetItemForKey("registers"));
+ if (regs)
+ {
+ const uint32_t num_regs = regs.GetSize();
+ PythonString name_pystr("name");
+ PythonString altname_pystr("alt-name");
+ PythonString bitsize_pystr("bitsize");
+ PythonString offset_pystr("offset");
+ PythonString encoding_pystr("encoding");
+ PythonString format_pystr("format");
+ PythonString set_pystr("set");
+ PythonString gcc_pystr("gcc");
+ PythonString dwarf_pystr("dwarf");
+ PythonString generic_pystr("generic");
+ for (uint32_t i=0; i<num_regs; ++i)
+ {
+ PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
+ if (reg_info_dict)
+ {
+ // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
+ RegisterInfo reg_info;
+ bzero (&reg_info, sizeof(reg_info));
+
+ reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
+ if (reg_info.name == NULL)
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString();
+
+ reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX);
+
+ if (reg_info.byte_offset == UINT32_MAX)
+ {
+ Clear();
+ return 0;
+ }
+ reg_info.byte_size = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0) / 8;
+
+ if (reg_info.byte_size == 0)
+ {
+ Clear();
+ return 0;
+ }
+
+ const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
+ if (format_cstr)
+ {
+ if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail())
+ {
+ Clear();
+ return 0;
+ }
+ }
+ else
+ reg_info.format = eFormatHex;
+
+ const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
+ if (encoding_cstr)
+ reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
+ else
+ reg_info.encoding = eEncodingUint;
+
+ const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
+ if (set >= m_sets.size())
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.kinds[lldb::eRegisterKindLLDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (reg_info_dict.GetItemForKeyAsString(generic_pystr));
+ const 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;
+
+ m_regs.push_back (reg_info);
+ m_set_reg_nums[set].push_back(i);
+
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ Finalize ();
+ }
+#endif
+ return 0;
+}
+
+
+void
+DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
+ ConstString &reg_name,
+ ConstString &reg_alt_name,
+ ConstString &set_name)
+{
+ const uint32_t reg_num = m_regs.size();
+ 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
+DynamicRegisterInfo::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
+DynamicRegisterInfo::GetNumRegisters() const
+{
+ return m_regs.size();
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisterSets() const
+{
+ return m_sets.size();
+}
+
+size_t
+DynamicRegisterInfo::GetRegisterDataByteSize() const
+{
+ return m_reg_data_byte_size;
+}
+
+const RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfoAtIndex (uint32_t i) const
+{
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+}
+
+const RegisterSet *
+DynamicRegisterInfo::GetRegisterSet (uint32_t i) const
+{
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+}
+
+uint32_t
+DynamicRegisterInfo::GetRegisterSetIndexByName (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);
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return m_sets.size() - 1;
+}
+
+uint32_t
+DynamicRegisterInfo::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
+DynamicRegisterInfo::Clear()
+{
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_set_names.clear();
+}
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
new file mode 100644
index 000000000000..a11cd333545f
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -0,0 +1,85 @@
+//===-- DynamicRegisterInfo.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_DynamicRegisterInfo_h_
+#define lldb_DynamicRegisterInfo_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+
+class DynamicRegisterInfo
+{
+public:
+ DynamicRegisterInfo ();
+
+ DynamicRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ virtual
+ ~DynamicRegisterInfo ();
+
+ size_t
+ SetRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ void
+ AddRegister (lldb_private::RegisterInfo &reg_info,
+ lldb_private::ConstString &reg_name,
+ lldb_private::ConstString &reg_alt_name,
+ lldb_private::ConstString &set_name);
+
+ void
+ Finalize ();
+
+ size_t
+ GetNumRegisters() const;
+
+ size_t
+ GetNumRegisterSets() const;
+
+ size_t
+ GetRegisterDataByteSize() const;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet (uint32_t i) const;
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name, bool can_create);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+ void
+ Clear();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from DynamicRegisterInfo can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb_private::RegisterInfo> reg_collection;
+ typedef std::vector <lldb_private::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_set_names;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+};
+
+#endif // lldb_DynamicRegisterInfo_h_
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
new file mode 100644
index 000000000000..499d6d766150
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -0,0 +1,274 @@
+//===-- InferiorCallPOSIX.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InferiorCallPOSIX.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+#include <sys/mman.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
+ addr_t addr, addr_t length, unsigned prot,
+ unsigned flags, addr_t fd, addr_t offset) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("mmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ addr_t prot_arg, flags_arg = 0;
+ if (prot == eMmapProtNone)
+ prot_arg = PROT_NONE;
+ else {
+ prot_arg = 0;
+ if (prot & eMmapProtExec)
+ prot_arg |= PROT_EXEC;
+ if (prot & eMmapProtRead)
+ prot_arg |= PROT_READ;
+ if (prot & eMmapProtWrite)
+ prot_arg |= PROT_WRITE;
+ }
+
+ if (flags & eMmapFlagsPrivate)
+ flags_arg |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_arg |= MAP_ANON;
+
+ AddressRange mmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
+ {
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ ThreadPlanCallFunction *call_function_thread_plan
+ = new ThreadPlanCallFunction (*thread,
+ mmap_range.GetBaseAddress(),
+ clang_void_ptr_type,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length,
+ &prot_arg,
+ &flags_arg,
+ &fd,
+ &offset);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+
+ allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (allocated_addr == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (allocated_addr == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
+ addr_t length) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("munmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ AddressRange munmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
+ {
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ munmap_range.GetBaseAddress(),
+ ClangASTType(),
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length));
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL || address == NULL)
+ return false;
+
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ ThreadPlanCallFunction *call_function_thread_plan
+ = new ThreadPlanCallFunction (*thread,
+ *address,
+ clang_void_ptr_type,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (returned_func == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (returned_func == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
new file mode 100644
index 000000000000..d8b6d0ed57fd
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -0,0 +1,43 @@
+//===-- InferiorCallPOSIX.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_InferiorCallPOSIX_h_
+#define lldb_InferiorCallPOSIX_h_
+
+// Inferior execution of POSIX functions.
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+class Process;
+
+enum MmapProt {
+ eMmapProtNone = 0,
+ eMmapProtExec = 1,
+ eMmapProtRead = 2,
+ eMmapProtWrite = 4
+};
+
+enum MmapFlags {
+ eMmapFlagsPrivate = 1,
+ eMmapFlagsAnon = 2
+};
+
+bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
+ lldb::addr_t addr, lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd, lldb::addr_t offset);
+
+bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
+
+bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func);
+
+} // namespace lldb_private
+
+#endif // lldb_InferiorCallPOSIX_h_
diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h
new file mode 100644
index 000000000000..4bb644e6efe6
--- /dev/null
+++ b/source/Plugins/Process/Utility/InstructionUtils.h
@@ -0,0 +1,136 @@
+//===-- InstructionUtils.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_InstructionUtils_h_
+#define lldb_InstructionUtils_h_
+
+// Common utilities for manipulating instruction bit fields.
+
+namespace lldb_private {
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 64-bit unsigned value.
+static inline uint64_t
+Bits64 (const uint64_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 64 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value.
+static inline uint32_t
+Bits32 (const uint32_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 32 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit value from the 'bit' position of a 32-bit unsigned value.
+static inline uint32_t
+Bit32 (const uint32_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1u;
+}
+
+static inline uint64_t
+Bit64 (const uint64_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1ull;
+}
+
+// Set the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value to 'val'.
+static inline void
+SetBits32(uint32_t &bits, const uint32_t msbit, const uint32_t lsbit, const uint32_t val)
+{
+ assert(msbit < 32 && lsbit < 32 && msbit >= lsbit);
+ uint32_t mask = ((1u << (msbit - lsbit + 1)) - 1);
+ bits &= ~(mask << lsbit);
+ bits |= (val & mask) << lsbit;
+}
+
+// Set the 'bit' position of a 32-bit unsigned value to 'val'.
+static inline void
+SetBit32(uint32_t &bits, const uint32_t bit, const uint32_t val)
+{
+ SetBits32(bits, bit, bit, val);
+}
+
+// Rotate a 32-bit unsigned value right by the specified amount.
+static inline uint32_t
+Rotr32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits >> amt) | (bits << ((32-amt)&31));
+}
+
+// Rotate a 32-bit unsigned value left by the specified amount.
+static inline uint32_t
+Rotl32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits << amt) | (bits >> ((32-amt)&31));
+}
+
+// Create a mask that starts at bit zero and includes "bit"
+static inline uint64_t
+MaskUpToBit (const uint64_t bit)
+{
+ return (1ull << (bit + 1ull)) - 1ull;
+}
+
+// Return an integer result equal to the number of bits of x that are ones.
+static inline uint32_t
+BitCount (uint64_t x)
+{
+ // c accumulates the total bits set in x
+ uint32_t c;
+ for (c = 0; x; ++c)
+ {
+ x &= x - 1; // clear the least significant bit set
+ }
+ return c;
+}
+
+static inline bool
+BitIsSet (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) != 0;
+}
+
+static inline bool
+BitIsClear (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) == 0;
+}
+
+static inline uint64_t
+UnsignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = value >> lsbit;
+ result &= MaskUpToBit (msbit - lsbit);
+ return result;
+}
+
+static inline int64_t
+SignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = UnsignedBits (value, msbit, lsbit);
+ if (BitIsSet(value, msbit))
+ {
+ // Sign extend
+ result |= ~MaskUpToBit (msbit - lsbit);
+ }
+ return result;
+}
+
+} // namespace lldb_private
+
+#endif // lldb_InstructionUtils_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
new file mode 100644
index 000000000000..4d77b6f20fdc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -0,0 +1,1226 @@
+//===-- RegisterContextDarwin_arm.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(__APPLE__)
+
+#include "RegisterContextDarwin_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#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/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.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
+};
+
+
+RegisterContextDarwin_arm::RegisterContextDarwin_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm::~RegisterContextDarwin_arm()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextDarwin_arm::DBG, reg) + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC))
+
+static RegisterInfo g_register_infos[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM, gdb_arm_r0, gpr_r0 }, NULL, NULL},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM, gdb_arm_r1, gpr_r1 }, NULL, NULL},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM, gdb_arm_r2, gpr_r2 }, NULL, NULL},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM, gdb_arm_r3, gpr_r3 }, NULL, NULL},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, gpr_r7 }, NULL, NULL},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, gpr_r11 }, NULL, NULL},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL},
+
+{ 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, 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, 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, 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
+RegisterContextDarwin_arm::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_arm::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_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
+RegisterContextDarwin_arm::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_arm::GetRegisterSet (size_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
+RegisterContextDarwin_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;
+}
+
+int
+RegisterContextDarwin_arm::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError (set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+
+int
+RegisterContextDarwin_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;
+}
+
+int
+RegisterContextDarwin_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
+RegisterContextDarwin_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
+RegisterContextDarwin_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_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.SetUInt32 (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.SetUInt32 (fpu.floats.s[reg], RegisterValue::eTypeFloat);
+ break;
+
+ case fpu_fpscr:
+ value.SetUInt32 (fpu.fpscr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32 (exc.exception);
+ break;
+ case exc_fsr:
+ value.SetUInt32 (exc.fsr);
+ break;
+ case exc_far:
+ value.SetUInt32 (exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_arm::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ 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.GetAsUInt32();
+ 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.GetAsUInt32();
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_fsr:
+ exc.fsr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextDarwin_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
+RegisterContextDarwin_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
+RegisterContextDarwin_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;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextDarwin_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 = UINT32_MAX;
+ if (g_num_supported_hw_breakpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_breakpoints = Bits32 (register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (g_num_supported_hw_breakpoints > 0)
+ g_num_supported_hw_breakpoints++;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints);
+
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ int 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
+// if (log) log->Printf ("RegisterContextDarwin_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
+// if (log) log->Printf ("RegisterContextDarwin_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();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+// else
+// {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+// }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareBreakpoint (uint32_t hw_index)
+{
+ int 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;
+// if (log) log->Printf ("RegisterContextDarwin_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
+RegisterContextDarwin_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 = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_watchpoints = Bits32 (register_DBGDIDR, 31, 28) + 1;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints);
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+// if (log) log->Printf ("RegisterContextDarwin_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;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int 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();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ int 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;
+// if (log) log->Printf ("RegisterContextDarwin_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;
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
new file mode 100644
index 000000000000..0bf204f57c80
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
@@ -0,0 +1,333 @@
+//===-- RegisterContextDarwin_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_RegisterContextDarwin_arm_h_
+#define liblldb_RegisterContextDarwin_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 privileged 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 RegisterContextDarwin_arm : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_arm();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ 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 QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } 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:
+
+ enum
+ {
+ GPRRegSet = 1, // ARM_THREAD_STATE
+ FPURegSet = 2, // ARM_VFP_STATE
+ EXCRegSet = 3, // ARM_EXCEPTION_STATE
+ DBGRegSet = 4 // ARM_DEBUG_STATE
+ };
+
+ 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;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ 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, int 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) == 0;
+ }
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ ReadDBG (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ int
+ WriteDBG ();
+
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+ {
+ return -1;
+ }
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ 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_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
new file mode 100644
index 000000000000..a94d1f538a28
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -0,0 +1,980 @@
+//===-- RegisterContextDarwin_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 <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_i386.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
+};
+
+RegisterContextDarwin_i386::RegisterContextDarwin_i386 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_i386::~RegisterContextDarwin_i386()
+{
+}
+
+
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::FPU, reg) + sizeof (RegisterContextDarwin_i386::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::EXC, reg) + sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_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(((RegisterContextDarwin_i386::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_##reg##i, LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL
+
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU) + sizeof (RegisterContextDarwin_i386::EXC))
+
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ======================= =================== ========================= ================== ================= ========== ===============
+ { DEFINE_GPR(eax , NULL) , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , gpr_eax }, NULL, NULL},
+ { DEFINE_GPR(ebx , NULL) , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , gpr_ebx }, NULL, NULL},
+ { DEFINE_GPR(ecx , NULL) , { gcc_ecx , dwarf_ecx , LLDB_INVALID_REGNUM , gdb_ecx , gpr_ecx }, NULL, NULL},
+ { DEFINE_GPR(edx , NULL) , { gcc_edx , dwarf_edx , LLDB_INVALID_REGNUM , gdb_edx , gpr_edx }, NULL, NULL},
+ { DEFINE_GPR(edi , NULL) , { gcc_edi , dwarf_edi , LLDB_INVALID_REGNUM , gdb_edi , gpr_edi }, NULL, NULL},
+ { DEFINE_GPR(esi , NULL) , { gcc_esi , dwarf_esi , LLDB_INVALID_REGNUM , gdb_esi , gpr_esi }, NULL, NULL},
+ { DEFINE_GPR(ebp , "fp") , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , gpr_ebp }, NULL, NULL},
+ { DEFINE_GPR(esp , "sp") , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , gpr_esp }, NULL, NULL},
+ { DEFINE_GPR(ss , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ss , gpr_ss }, NULL, NULL},
+ { DEFINE_GPR(eflags , "flags") , { gcc_eflags , dwarf_eflags , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , gpr_eflags }, NULL, NULL},
+ { DEFINE_GPR(eip , "pc") , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , gpr_eip }, NULL, NULL},
+ { DEFINE_GPR(cs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR(ds , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , gpr_ds }, NULL, NULL},
+ { DEFINE_GPR(es , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_es , gpr_es }, NULL, NULL},
+ { DEFINE_GPR(fs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR(gs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask}, NULL, NULL},
+ { 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, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextDarwin_i386::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_i386::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_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
+RegisterContextDarwin_i386::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_i386::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_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
+RegisterContextDarwin_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]);
+ }
+ }
+}
+
+
+
+int
+RegisterContextDarwin_i386::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_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 -1;
+}
+
+int
+RegisterContextDarwin_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 -1;
+}
+
+bool
+RegisterContextDarwin_i386::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_i386::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ 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
+RegisterContextDarwin_i386::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ 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.GetAsUInt32();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ 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, value.GetBytes(), value.GetByteSize());
+ 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, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_i386::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ 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
+RegisterContextDarwin_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() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_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;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+RegisterContextDarwin_i386::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(false) != 0)
+ 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() == 0;
+}
+
+
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
new file mode 100644
index 000000000000..a588494f9dcf
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
@@ -0,0 +1,269 @@
+//===-- RegisterContextDarwin_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_RegisterContextDarwin_i386_h_
+#define liblldb_RegisterContextDarwin_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_i386 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_i386(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_i386();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ 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;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ 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, int 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) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *title);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ 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_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
new file mode 100644
index 000000000000..433782fe20c0
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -0,0 +1,1066 @@
+//===-- RegisterContextDarwin_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 <stdarg.h>
+#include <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_x86_64.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
+};
+
+RegisterContextDarwin_x86_64::RegisterContextDarwin_x86_64 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext (thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_x86_64::~RegisterContextDarwin_x86_64()
+{
+}
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::FPU, reg) + sizeof (RegisterContextDarwin_x86_64::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::EXC, reg) + sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_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(((RegisterContextDarwin_x86_64::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU) + sizeof (RegisterContextDarwin_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ====================== =================== ========================== ==================== =================== ========== ===============
+ { DEFINE_GPR (rax , NULL) , { gcc_dwarf_gpr_rax , gcc_dwarf_gpr_rax , LLDB_INVALID_REGNUM , gdb_gpr_rax , gpr_rax }, NULL, NULL},
+ { DEFINE_GPR (rbx , NULL) , { gcc_dwarf_gpr_rbx , gcc_dwarf_gpr_rbx , LLDB_INVALID_REGNUM , gdb_gpr_rbx , gpr_rbx }, NULL, NULL},
+ { DEFINE_GPR (rcx , NULL) , { gcc_dwarf_gpr_rcx , gcc_dwarf_gpr_rcx , LLDB_INVALID_REGNUM , gdb_gpr_rcx , gpr_rcx }, NULL, NULL},
+ { DEFINE_GPR (rdx , NULL) , { gcc_dwarf_gpr_rdx , gcc_dwarf_gpr_rdx , LLDB_INVALID_REGNUM , gdb_gpr_rdx , gpr_rdx }, NULL, NULL},
+ { DEFINE_GPR (rdi , NULL) , { gcc_dwarf_gpr_rdi , gcc_dwarf_gpr_rdi , LLDB_INVALID_REGNUM , gdb_gpr_rdi , gpr_rdi }, NULL, NULL},
+ { DEFINE_GPR (rsi , NULL) , { gcc_dwarf_gpr_rsi , gcc_dwarf_gpr_rsi , LLDB_INVALID_REGNUM , gdb_gpr_rsi , gpr_rsi }, NULL, NULL},
+ { DEFINE_GPR (rbp , "fp") , { gcc_dwarf_gpr_rbp , gcc_dwarf_gpr_rbp , LLDB_REGNUM_GENERIC_FP , gdb_gpr_rbp , gpr_rbp }, NULL, NULL},
+ { DEFINE_GPR (rsp , "sp") , { gcc_dwarf_gpr_rsp , gcc_dwarf_gpr_rsp , LLDB_REGNUM_GENERIC_SP , gdb_gpr_rsp , gpr_rsp }, NULL, NULL},
+ { DEFINE_GPR (r8 , NULL) , { gcc_dwarf_gpr_r8 , gcc_dwarf_gpr_r8 , LLDB_INVALID_REGNUM , gdb_gpr_r8 , gpr_r8 }, NULL, NULL},
+ { DEFINE_GPR (r9 , NULL) , { gcc_dwarf_gpr_r9 , gcc_dwarf_gpr_r9 , LLDB_INVALID_REGNUM , gdb_gpr_r9 , gpr_r9 }, NULL, NULL},
+ { DEFINE_GPR (r10 , NULL) , { gcc_dwarf_gpr_r10 , gcc_dwarf_gpr_r10 , LLDB_INVALID_REGNUM , gdb_gpr_r10 , gpr_r10 }, NULL, NULL},
+ { DEFINE_GPR (r11 , NULL) , { gcc_dwarf_gpr_r11 , gcc_dwarf_gpr_r11 , LLDB_INVALID_REGNUM , gdb_gpr_r11 , gpr_r11 }, NULL, NULL},
+ { DEFINE_GPR (r12 , NULL) , { gcc_dwarf_gpr_r12 , gcc_dwarf_gpr_r12 , LLDB_INVALID_REGNUM , gdb_gpr_r12 , gpr_r12 }, NULL, NULL},
+ { DEFINE_GPR (r13 , NULL) , { gcc_dwarf_gpr_r13 , gcc_dwarf_gpr_r13 , LLDB_INVALID_REGNUM , gdb_gpr_r13 , gpr_r13 }, NULL, NULL},
+ { DEFINE_GPR (r14 , NULL) , { gcc_dwarf_gpr_r14 , gcc_dwarf_gpr_r14 , LLDB_INVALID_REGNUM , gdb_gpr_r14 , gpr_r14 }, NULL, NULL},
+ { DEFINE_GPR (r15 , NULL) , { gcc_dwarf_gpr_r15 , gcc_dwarf_gpr_r15 , LLDB_INVALID_REGNUM , gdb_gpr_r15 , gpr_r15 }, NULL, NULL},
+ { DEFINE_GPR (rip , "pc") , { gcc_dwarf_gpr_rip , gcc_dwarf_gpr_rip , LLDB_REGNUM_GENERIC_PC , gdb_gpr_rip , gpr_rip }, NULL, NULL},
+ { DEFINE_GPR (rflags, "flags") , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags , gpr_rflags }, NULL, NULL},
+ { DEFINE_GPR (cs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR (fs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR (gs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask }, NULL, NULL},
+ { 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, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+
+void
+RegisterContextDarwin_x86_64::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+
+const RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDarwin_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
+RegisterContextDarwin_x86_64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_x86_64::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+int
+RegisterContextDarwin_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
+RegisterContextDarwin_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.16" PRIx64, g_register_infos[reg].name, (&gpr.rax)[reg]);
+ }
+ }
+}
+
+int
+RegisterContextDarwin_x86_64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_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 -1;
+}
+
+int
+RegisterContextDarwin_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 -1;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ 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:
+ value.SetBytes(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ 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:
+ value.SetBytes(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ 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
+RegisterContextDarwin_x86_64::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ 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.GetAsUInt64();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ 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, value.GetBytes(), value.GetByteSize());
+ 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:
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ 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
+RegisterContextDarwin_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() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_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;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextDarwin_x86_64::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(true) != 0)
+ 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() == 0;
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
new file mode 100644
index 000000000000..4b8127af997c
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
@@ -0,0 +1,274 @@
+//===-- RegisterContextDarwin_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_RegisterContextDarwin_x86_64_h_
+#define liblldb_RegisterContextDarwin_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 RegisterContextDarwin_x86_64 : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextDarwin_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_x86_64();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ 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:
+
+ 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;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ 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, int 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) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *format, ...);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ 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_private::RegisterInfo *
+ GetRegisterInfos ();
+
+};
+
+#endif // liblldb_RegisterContextDarwin_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
new file mode 100644
index 000000000000..1e282ce74f2e
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -0,0 +1,137 @@
+//===-- RegisterContextDummy.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/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextDummy.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDummy::RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size) :
+RegisterContext (thread, concrete_frame_idx)
+{
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = NULL;
+ m_pc_reg_info.value_regs = NULL;
+ m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextDummy::~RegisterContextDummy ()
+{
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void
+RegisterContextDummy::InvalidateAllRegisters () {}
+
+size_t
+RegisterContextDummy::GetRegisterCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDummy::GetRegisterInfoAtIndex (size_t reg)
+{
+ if (reg)
+ return NULL;
+ return &m_pc_reg_info;
+}
+
+size_t
+RegisterContextDummy::GetRegisterSetCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextDummy::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set)
+ return NULL;
+ return &m_reg_set0;
+}
+
+bool
+RegisterContextDummy::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC)
+ {
+ value.SetUInt(LLDB_INVALID_ADDRESS, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextDummy::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.h b/source/Plugins/Process/Utility/RegisterContextDummy.h
new file mode 100644
index 000000000000..ee8d5a134bbc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextDummy.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_RegisterContextDummy_h_
+#define lldb_RegisterContextDummy_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextDummy : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextDummy> SharedPtr;
+
+ RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextDummy ();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextDummy);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextDummy_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
new file mode 100644
index 000000000000..1ffc30da5762
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -0,0 +1,1541 @@
+//===-- RegisterContextLLDB.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/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextLLDB::RegisterContextLLDB
+(
+ Thread& thread,
+ const SharedPtr &next_frame,
+ SymbolContext& sym_ctx,
+ uint32_t frame_number,
+ UnwindLLDB& unwind_lldb
+) :
+ RegisterContext (thread, frame_number),
+ m_thread(thread),
+ m_fast_unwind_plan_sp (),
+ m_full_unwind_plan_sp (),
+ m_all_registers_available(false),
+ m_frame_type (-1),
+ m_cfa (LLDB_INVALID_ADDRESS),
+ m_start_pc (),
+ m_current_pc (),
+ m_current_offset (0),
+ m_current_offset_backed_up_one (0),
+ m_sym_ctx(sym_ctx),
+ m_sym_ctx_valid (false),
+ m_frame_number (frame_number),
+ m_registers(),
+ m_parent_unwind (unwind_lldb)
+{
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+
+ if (IsFrameZero ())
+ {
+ InitializeZerothFrame ();
+ }
+ else
+ {
+ InitializeNonZerothFrame ();
+ }
+
+ // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
+ if (IsFrameZero()
+ || next_frame->m_frame_type == eSigtrampFrame
+ || next_frame->m_frame_type == eDebuggerFrame)
+ {
+ m_all_registers_available = true;
+ }
+}
+
+// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
+// executing frame.
+
+void
+RegisterContextLLDB::InitializeZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
+
+ if (reg_ctx_sp.get() == NULL)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t current_pc = reg_ctx_sp->GetPC();
+
+ if (current_pc == LLDB_INVALID_ADDRESS)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ // (which would be a no-op in frame 0 where we get it from the register set,
+ // but still a good idea to make the call here for other ABIs that may exist.)
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ current_pc = abi->FixCodeAddress(current_pc);
+
+ // Initialize m_current_pc, an Address object, based on current_pc, an addr_t.
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if (pc_module_sp.get()
+ && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
+
+ static ConstString g_sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ m_frame_type = eNormalFrame;
+ }
+
+ // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ if (m_current_pc.GetSection() == m_start_pc.GetSection())
+ {
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ }
+ else if (m_current_pc.GetModule() == m_start_pc.GetModule())
+ {
+ // This means that whatever symbol we kicked up isn't really correct
+ // --- we should not cross section boundaries ... We really should NULL out
+ // the function/symbol in this case unless there is a bad assumption
+ // here due to inlined functions?
+ m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
+ }
+ m_current_offset_backed_up_one = m_current_offset;
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ // We've set m_frame_type and m_sym_ctx before these calls.
+
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("%s", active_row_strm.GetString().c_str());
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ cfa_offset = active_row->GetCFAOffset ();
+ m_cfa = cfa_regval + cfa_offset;
+
+ UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),
+ (uint64_t) m_cfa,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+}
+
+// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it
+// to provide things like its current pc value.
+
+void
+RegisterContextLLDB::InitializeNonZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (IsFrameZero ())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ if (!m_thread.GetRegisterContext())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t pc;
+ if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ UnwindLogMsg ("could not get pc value");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (log)
+ {
+ UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
+ addr_t reg_val;
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+ UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+ UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
+ }
+
+ // A pc of 0x0 means it's the end of the stack crawl
+ if (pc == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+
+ // Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
+ uint32_t permissions;
+ if (process->GetLoadAddressPermissions(pc, permissions)
+ && (permissions & ePermissionsExecutable) == 0)
+ {
+ // If this is the second frame off the stack, we may have unwound the first frame
+ // incorrectly. But using the architecture default unwind plan may get us back on
+ // track -- albeit possibly skipping a real frame. Give this frame a clearly-invalid
+ // pc and see if we can get any further.
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero())
+ {
+ UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.",
+ (uint64_t) pc);
+ m_frame_type = eSkipFrame;
+ }
+ else
+ {
+ // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ if (abi)
+ {
+ m_fast_unwind_plan_sp.reset ();
+ m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ m_all_registers_available = false;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
+ if (row.get())
+ {
+ uint32_t cfa_regnum = row->GetCFARegister();
+ int cfa_offset = row->GetCFAOffset();
+ if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
+ {
+ UnwindLogMsg ("failed to get cfa value");
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ return;
+ }
+ m_cfa = cfa_regval + cfa_offset;
+
+ // A couple of sanity checks..
+ if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // cfa_regval should point into the stack memory; if we can query memory region permissions,
+ // see if the memory is allocated & readable.
+ if (process->GetLoadAddressPermissions(cfa_regval, permissions)
+ && (permissions & ePermissionsReadable) == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+ else
+ {
+ UnwindLogMsg ("could not find a row for function offset zero");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa);
+ return;
+ }
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if ((pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+
+ bool decr_pc_and_recompute_addr_range = false;
+
+ // If the symbol lookup failed...
+ if (m_sym_ctx_valid == false)
+ decr_pc_and_recompute_addr_range = true;
+
+ // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
+ // and our "current" pc is the start of a function...
+ if (m_sym_ctx_valid
+ && GetNextFrame()->m_frame_type != eSigtrampFrame
+ && GetNextFrame()->m_frame_type != eDebuggerFrame
+ && addr_range.GetBaseAddress().IsValid()
+ && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
+ && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
+ {
+ decr_pc_and_recompute_addr_range = true;
+ }
+
+ // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
+ // value is pointing to the next function, e.g. if a function ends with a CALL instruction.
+ // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
+ // to the ABI plugin and consult that.
+ if (decr_pc_and_recompute_addr_range)
+ {
+ Address temporary_pc(m_current_pc);
+ temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+ if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+ }
+
+ // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ m_current_offset_backed_up_one = m_current_offset;
+ if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
+ {
+ m_current_offset_backed_up_one--;
+ if (m_sym_ctx_valid)
+ m_current_pc.SetOffset(m_current_pc.GetOffset() - 1);
+ }
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ static ConstString sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name)
+ || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ }
+
+ // We've set m_frame_type and m_sym_ctx before this call.
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+
+ // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
+ // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
+
+ if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ else
+ {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ cfa_offset = active_row->GetCFAOffset ();
+ m_cfa = cfa_regval + cfa_offset;
+
+ UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
+
+ // A couple of sanity checks..
+ if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // If we have a bad stack setup, we can get the same CFA value multiple times -- or even
+ // more devious, we can actually oscillate between two CFA values. Detect that here and
+ // break out to avoid a possible infinite loop in lldb trying to unwind the stack.
+ addr_t next_frame_cfa;
+ addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
+ if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa))
+ {
+ bool repeating_frames = false;
+ if (next_frame_cfa == m_cfa)
+ {
+ repeating_frames = true;
+ }
+ else
+ {
+ if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
+ && next_next_frame_cfa == m_cfa)
+ {
+ repeating_frames = true;
+ }
+ }
+ if (repeating_frames && abi->FunctionCallsChangeCFA())
+ {
+ UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa);
+}
+
+
+bool
+RegisterContextLLDB::IsFrameZero () const
+{
+ return m_frame_number == 0;
+}
+
+
+// Find a fast unwind plan for this frame, if possible.
+//
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFastUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ return unwind_plan_sp;
+
+ if (IsFrameZero ())
+ return unwind_plan_sp;
+
+ FuncUnwindersSP func_unwinders_sp (pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx));
+ if (!func_unwinders_sp)
+ return unwind_plan_sp;
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge.
+ if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame)
+ return unwind_plan_sp;
+
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
+ if (unwind_plan_sp)
+ {
+ if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ if (m_fast_unwind_plan_sp)
+ UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan");
+ else
+ UnwindLogMsgVerbose ("frame");
+ }
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ else
+ {
+ unwind_plan_sp.reset();
+ }
+ }
+ return unwind_plan_sp;
+}
+
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFullUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ }
+
+ bool behaves_like_zeroth_frame = false;
+ if (IsFrameZero ()
+ || GetNextFrame()->m_frame_type == eSigtrampFrame
+ || GetNextFrame()->m_frame_type == eDebuggerFrame)
+ {
+ behaves_like_zeroth_frame = true;
+ // If this frame behaves like a 0th frame (currently executing or
+ // interrupted asynchronously), all registers can be retrieved.
+ m_all_registers_available = true;
+ }
+
+ // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
+ // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
+ // Also, if this Process can report on memory region attributes, any non-executable region means
+ // we jumped through a bad function pointer - handle the same way as 0x0.
+ // Note, if the symbol context has a function for the symbol, then we don't need to do this check.
+
+ if ((!m_sym_ctx_valid || m_sym_ctx.function == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid())
+ {
+ uint32_t permissions;
+ addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
+ if (current_pc_addr == 0
+ || (process->GetLoadAddressPermissions(current_pc_addr, permissions)
+ && (permissions & ePermissionsExecutable) == 0))
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ }
+
+ // No Module for the current pc, try using the architecture default unwind.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ {
+ m_frame_type = eNormalFrame;
+ return arch_default_unwind_plan_sp;
+ }
+
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid)
+ {
+ func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ }
+
+ // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer).
+ // Try using the eh_frame information relative to the current PC,
+ // and finally fall back on the architectural default unwind.
+ if (!func_unwinders_sp)
+ {
+ DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ?
+ pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr;
+
+ m_frame_type = eNormalFrame;
+ if (eh_frame && m_current_pc.IsValid())
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ // Even with -fomit-frame-pointer, we can try eh_frame to get back on track.
+ if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+ return arch_default_unwind_plan_sp;
+ }
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge. On Mac OS X this knowledge
+ // is properly encoded in the eh_frame section, so prefer that if available.
+ // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
+ // how to unwind out of sigtramp.
+ if (m_frame_type == eSigtrampFrame)
+ {
+ m_fast_unwind_plan_sp.reset();
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ return unwind_plan_sp;
+ }
+
+ // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
+ // This comes up if we have hand-written functions in a Module and hand-written eh_frame. The assembly
+ // instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
+ // right thing. It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
+ // (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
+ // But there is not.
+ if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
+ if (behaves_like_zeroth_frame)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
+ // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If nothing else, use the architectural default UnwindPlan and hope that does the job.
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ return arch_default_unwind_plan_sp;
+}
+
+
+void
+RegisterContextLLDB::InvalidateAllRegisters ()
+{
+ m_frame_type = eNotAValidFrame;
+}
+
+size_t
+RegisterContextLLDB::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextLLDB::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextLLDB::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount ();
+}
+
+const RegisterSet *
+RegisterContextLLDB::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->ReadRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size);
+ break;
+
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (ReadRegisterValueFromMemory(reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+bool
+RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->WriteRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (WriteRegisterValueToMemory (reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+
+bool
+RegisterContextLLDB::IsValid () const
+{
+ return m_frame_type != eNotAValidFrame;
+}
+
+// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther
+// up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after
+// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the
+// user knows we're displaying bad data and we may have skipped one frame of their real program in the
+// process of getting back on track.
+
+bool
+RegisterContextLLDB::IsSkipFrame () const
+{
+ return m_frame_type == eSkipFrame;
+}
+
+// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
+
+enum UnwindLLDB::RegisterSearchResult
+RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc)
+{
+ // Have we already found this register location?
+ if (!m_registers.empty())
+ {
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator;
+ iterator = m_registers.find (lldb_regnum);
+ if (iterator != m_registers.end())
+ {
+ regloc = iterator->second;
+ UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ uint32_t sp_regnum = LLDB_INVALID_REGNUM;
+ uint32_t pc_regnum = LLDB_INVALID_REGNUM;
+ m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum);
+ m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum);
+
+ // Are we looking for the CALLER's stack pointer? The stack pointer is defined to be the same as THIS frame's
+ // CFA so just return the CFA value. This is true on x86-32/x86-64 at least.
+ if (sp_regnum != LLDB_INVALID_REGNUM && sp_regnum == lldb_regnum)
+ {
+ // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
+ assert (sizeof (addr_t) <= sizeof (uint64_t));
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ // Look through the available UnwindPlans for the register location.
+
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ bool have_unwindplan_regloc = false;
+ RegisterKind unwindplan_registerkind = (RegisterKind)-1;
+
+ if (m_fast_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ uint32_t row_regnum;
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ {
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum);
+ have_unwindplan_regloc = true;
+ }
+ }
+
+ if (!have_unwindplan_regloc)
+ {
+ // m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet
+ if (!m_full_unwind_plan_sp)
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ if (m_full_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
+ uint32_t row_regnum;
+ bool row_register_rewritten_to_return_address_reg = false;
+
+ // If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
+ // look for the return address register number in the UnwindPlan's row.
+ if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
+ {
+ row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister();
+ row_register_rewritten_to_return_address_reg = true;
+ UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead",
+ row_regnum);
+ }
+ else
+ {
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ {
+ if (unwindplan_registerkind == eRegisterKindGeneric)
+ UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum);
+ else
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ }
+
+ // This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and
+ // it hasn't been saved anywhere yet -- that is, it's still live in the actual register.
+ // Handle this specially.
+
+ if (have_unwindplan_regloc == false
+ && row_register_rewritten_to_return_address_reg == true
+ && IsFrameZero()
+ && row_regnum != LLDB_INVALID_REGNUM)
+ {
+ uint32_t ra_regnum_in_lldb_reg_numbering;
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering))
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering;
+ m_registers[lldb_regnum] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // If this architecture stores the return address in a register (it defines a Return Address register)
+ // and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the
+ // RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this
+ // is an impossible situation and the instruction emulation code has likely been misled.
+ // If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the
+ // instruction emulation came up with and fall back to the architecture's Default UnwindPlan so
+ // the stack walk can get past this point.
+
+ // Special note: If the Full UnwindPlan was generated from the compiler, don't second-guess it
+ // when we're at a call site location.
+
+ // arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering
+ uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM;
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum)
+ && arch_default_ra_regnum != LLDB_INVALID_REGNUM
+ && pc_regnum != LLDB_INVALID_REGNUM
+ && pc_regnum == lldb_regnum
+ && unwindplan_regloc.IsInOtherRegister()
+ && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum
+ && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
+ && !m_all_registers_available)
+ {
+ UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // Throw away the full unwindplan; install the arch default unwindplan
+ InvalidateFullUnwindPlan();
+
+ // Now re-fetch the pc value we're searching for
+ uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM;
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg)
+ && arch_default_pc_reg != LLDB_INVALID_REGNUM
+ && active_row
+ && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ }
+ else
+ {
+ have_unwindplan_regloc = false;
+ }
+ }
+ }
+ }
+
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (have_unwindplan_regloc == false)
+ {
+ // If a volatile register is being requested, we don't want to forward the next frame's register contents
+ // up the stack -- the register is not retrievable at this frame.
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ if (reg_info && abi->RegisterIsVolatile (reg_info))
+ {
+ UnwindLogMsg ("did not supply reg location for %d because it is volatile", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
+ }
+ }
+
+ if (IsFrameZero ())
+ {
+ // This is frame 0 - we should return the actual live register context value
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ new_regloc.location.register_number = lldb_regnum;
+ m_registers[lldb_regnum] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ // unwindplan_regloc has valid contents about where to retrieve the register
+ if (unwindplan_regloc.IsUnspecified())
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
+ m_registers[lldb_regnum] = new_regloc;
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ if (unwindplan_regloc.IsSame())
+ {
+ if (IsFrameZero ())
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ else
+ {
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (unwindplan_regloc.IsCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa + offset;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = m_cfa + offset;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsInOtherRegister())
+ {
+ uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
+ uint32_t row_regnum_in_lldb;
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb))
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = row_regnum_in_lldb;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
+ {
+ DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
+ unwindplan_regloc.GetDWARFExpressionLength(),
+ process->GetByteOrder(), process->GetAddressByteSize());
+ DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
+ dwarfexpr.SetRegisterKind (unwindplan_registerkind);
+ Value result;
+ Error error;
+ if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
+ {
+ addr_t val;
+ val = result.GetScalar().ULongLong();
+ if (unwindplan_regloc.IsDWARFExpression())
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = val;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = val;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+ UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+
+ // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.
+
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+}
+
+// If the Full unwindplan has been determined to be incorrect, this method will
+// replace it with the architecture's default unwindplna, if one is defined.
+// It will also find the FuncUnwinders object for this function and replace the
+// Full unwind method for the function there so we don't use the errant Full unwindplan
+// again in the future of this debug session.
+// We're most likely doing this because the Full unwindplan was generated by assembly
+// instruction profiling and the profiler got something wrong.
+
+void
+RegisterContextLLDB::InvalidateFullUnwindPlan ()
+{
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ if (arch_default_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
+ {
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule())
+ {
+ func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ if (func_unwinders_sp)
+ {
+ func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
+ }
+ }
+ m_registers.clear();
+ m_full_unwind_plan_sp = arch_default_unwind_plan_sp;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
+ {
+ m_cfa = cfa_regval + active_row->GetCFAOffset ();
+ }
+
+ UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.",
+ original_full_unwind_plan_sp->GetSourceName().GetCString(), arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ }
+ }
+ }
+}
+
+// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
+// this frame called. e.g.
+//
+// foo () { }
+// bar () { foo (); }
+// main () { bar (); }
+//
+// stopped in foo() so
+// frame 0 - foo
+// frame 1 - bar
+// frame 2 - main
+// and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask
+// where frame 0 (the "next" frame) saved that and retrieve the value.
+
+bool
+RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value)
+{
+ if (!IsValid())
+ return false;
+
+ uint32_t lldb_regnum;
+ if (register_kind == eRegisterKindLLDB)
+ {
+ lldb_regnum = regnum;
+ }
+ else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum))
+ {
+ return false;
+ }
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ RegisterValue reg_value;
+ // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers
+ if (IsFrameZero ())
+ {
+ if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+ }
+
+ bool pc_register = false;
+ uint32_t generic_regnum;
+ if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+ else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum)
+ && generic_regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register))
+ {
+ return false;
+ }
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+}
+
+// Find the value of a register in THIS frame
+
+bool
+RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->ReadRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
+}
+
+bool
+RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->WriteRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return WriteRegisterValueToRegisterLocation (regloc, reg_info, value);
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp)
+{
+ return false;
+}
+
+// Retrieve the pc value for THIS from
+
+bool
+RegisterContextLLDB::GetCFA (addr_t& cfa)
+{
+ if (!IsValid())
+ {
+ return false;
+ }
+ if (m_cfa == LLDB_INVALID_ADDRESS)
+ {
+ return false;
+ }
+ cfa = m_cfa;
+ return true;
+}
+
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetNextFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ if (m_frame_number == 0)
+ return regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1);
+}
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetPrevFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number + 1);
+}
+
+// Retrieve the address of the start of the function of THIS frame
+
+bool
+RegisterContextLLDB::GetStartPC (addr_t& start_pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (!m_start_pc.IsValid())
+ {
+ return ReadPC (start_pc);
+ }
+ start_pc = m_start_pc.GetLoadAddress (CalculateTarget().get());
+ return true;
+}
+
+// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
+
+bool
+RegisterContextLLDB::ReadPC (addr_t& pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ // A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk.
+ // On the currently executing frame (or such a frame interrupted asynchronously by sigtramp et al) this may
+ // occur if code has jumped through a NULL pointer -- we want to be able to unwind past that frame to help
+ // find the bug.
+
+ if (m_all_registers_available == false
+ && (pc == 0 || pc == 1))
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void
+RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
+void
+RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h
new file mode 100644
index 000000000000..dc6d8c61fa4a
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -0,0 +1,212 @@
+//===-- RegisterContextLLDB.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_RegisterContextLLDB_h_
+#define lldb_RegisterContextLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "UnwindLLDB.h"
+
+namespace lldb_private {
+
+class UnwindLLDB;
+
+class RegisterContextLLDB : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextLLDB> SharedPtr;
+
+ RegisterContextLLDB (lldb_private::Thread &thread,
+ const SharedPtr& next_frame,
+ lldb_private::SymbolContext& sym_ctx,
+ uint32_t frame_number, lldb_private::UnwindLLDB& unwind_lldb);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextLLDB () { }
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ bool
+ IsValid () const;
+
+ bool
+ GetCFA (lldb::addr_t& cfa);
+
+ bool
+ GetStartPC (lldb::addr_t& start_pc);
+
+ bool
+ ReadPC (lldb::addr_t& start_pc);
+
+private:
+
+ enum FrameType
+ {
+ eNormalFrame,
+ eSigtrampFrame,
+ eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger
+ eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet
+ eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack
+ };
+
+ // UnwindLLDB needs to pass around references to RegisterLocations
+ friend class UnwindLLDB;
+
+ // Indicates whether this frame is frame zero -- the currently
+ // executing frame -- or not.
+ bool
+ IsFrameZero () const;
+
+ void
+ InitializeZerothFrame ();
+
+ void
+ InitializeNonZerothFrame();
+
+ SharedPtr
+ GetNextFrame () const;
+
+ SharedPtr
+ GetPrevFrame () const;
+
+ // A SkipFrame occurs when the unwind out of frame 0 didn't go right -- we've got one bogus frame at frame #1.
+ // There is a good chance we'll get back on track if we follow the frame pointer chain (or whatever is appropriate
+ // on this ABI) so we allow one invalid frame to be in the stack. Ideally we'll mark this frame specially at some
+ // point and indicate to the user that the unwinder had a hiccup. Often when this happens we will miss a frame of
+ // the program's actual stack in the unwind and we want to flag that for the user somehow.
+ bool
+ IsSkipFrame () const;
+
+ // Provide a location for where THIS function saved the CALLER's register value
+ // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this
+ // function didn't modify/use.
+ //
+ // The RegisterLocation type may be set to eRegisterNotAvailable -- this will happen for a volatile register
+ // being queried mid-stack. Instead of floating frame 0's contents of that register up the stack (which may
+ // or may not be the value of that reg when the function was executing), we won't return any value.
+ //
+ // If a non-volatile register (a "preserved" register) is requested mid-stack and no frames "below" the requested
+ // stack have saved the register anywhere, it is safe to assume that frame 0's register values are still the same
+ // as the requesting frame's.
+ lldb_private::UnwindLLDB::RegisterSearchResult
+ SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc);
+
+ bool
+ ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ void
+ InvalidateFullUnwindPlan ();
+
+ // Get the contents of a general purpose (address-size) register for this frame
+ // (usually retrieved from the next frame)
+ bool
+ ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value);
+
+ lldb::UnwindPlanSP
+ GetFastUnwindPlanForFrame ();
+
+ lldb::UnwindPlanSP
+ GetFullUnwindPlanForFrame ();
+
+ void
+ UnwindLogMsg (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ lldb_private::Thread& m_thread;
+
+ ///
+ // The following tell us how to retrieve the CALLER's register values (ie the "previous" frame, aka the frame above)
+ // i.e. where THIS frame saved them
+ ///
+
+ lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
+ lldb::UnwindPlanSP m_full_unwind_plan_sp;
+ bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs?
+ int m_frame_type; // enum FrameType
+
+ lldb::addr_t m_cfa;
+ lldb_private::Address m_start_pc;
+ lldb_private::Address m_current_pc;
+
+ int m_current_offset; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+
+ int m_current_offset_backed_up_one; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+ // On architectures where the return address on the stack points
+ // to the instruction after the CALL, this value will have 1
+ // subtracted from it. Else a function that ends in a CALL will
+ // have an offset pointing into the next function's address range.
+ // m_current_pc has the actual address of the "current" pc.
+
+ lldb_private::SymbolContext& m_sym_ctx;
+ bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to use m_sym_ctx
+
+ uint32_t m_frame_number; // What stack frame this RegisterContext is
+
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation> m_registers; // where to find reg values for this frame
+
+ lldb_private::UnwindLLDB& m_parent_unwind; // The UnwindLLDB that is creating this RegisterContextLLDB
+
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextLLDB_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 000000000000..2c3eee452488
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -0,0 +1,206 @@
+//===-- 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/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMacOSXFrameBackchain constructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_cursor (cursor),
+ m_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain()
+{
+}
+
+void
+RegisterContextMacOSXFrameBackchain::InvalidateAllRegisters ()
+{
+ m_cursor_is_valid = false;
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const RegisterSet *
+RegisterContextMacOSXFrameBackchain::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!m_cursor_is_valid)
+ return false;
+
+ uint64_t reg_value = LLDB_INVALID_ADDRESS;
+
+ 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.fp;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ case eEncodingVector:
+ break;
+
+ case eEncodingUint:
+ case eEncodingSint:
+ value.SetUInt(reg_value, reg_info->byte_size);
+ return true;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ break;
+
+ // TOOD: need a better way to detect when "long double" types are
+ // the same bytes size as "double"
+#if !defined(__arm__)
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ break;
+#endif
+ }
+ break;
+ }
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &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::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 000000000000..449e053e5ef1
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -0,0 +1,77 @@
+//===-- 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,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor);
+
+ virtual
+ ~RegisterContextMacOSXFrameBackchain ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ 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/RegisterContextMach_arm.cpp b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
new file mode 100644
index 000000000000..7ceb536272f4
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
@@ -0,0 +1,87 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextMach_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_arm::~RegisterContextMach_arm()
+{
+}
+
+int
+RegisterContextMach_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ mach_msg_type_number_t count = DBGWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&dbg, &count);
+}
+
+int
+RegisterContextMach_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&dbg, DBGWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
new file mode 100644
index 000000000000..e97a4bfff2b6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
@@ -0,0 +1,56 @@
+//===-- 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 "RegisterContextDarwin_arm.h"
+
+class RegisterContextMach_arm : public RegisterContextDarwin_arm
+{
+public:
+
+ RegisterContextMach_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_arm();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
+};
+
+#endif // liblldb_RegisterContextMach_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
new file mode 100644
index 000000000000..3d6c9a6baca6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
@@ -0,0 +1,72 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_i386 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_i386::~RegisterContextMach_i386()
+{
+}
+
+int
+RegisterContextMach_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
new file mode 100644
index 000000000000..ad0f69d1c052
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
@@ -0,0 +1,49 @@
+//===-- 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 "RegisterContextDarwin_i386.h"
+
+class RegisterContextMach_i386 : public RegisterContextDarwin_i386
+{
+public:
+
+ RegisterContextMach_i386(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_i386();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
new file mode 100644
index 000000000000..f03685e1313f
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,72 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_x86_64 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
+{
+}
+
+int
+RegisterContextMach_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
new file mode 100644
index 000000000000..9e6dfa395500
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
@@ -0,0 +1,49 @@
+//===-- 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 "RegisterContextDarwin_x86_64.h"
+
+class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+
+ RegisterContextMach_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_x86_64();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
new file mode 100644
index 000000000000..8c33a6814acc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -0,0 +1,174 @@
+//===-- RegisterContextMemory.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "DynamicRegisterInfo.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMemory constructor
+//----------------------------------------------------------------------
+RegisterContextMemory::RegisterContextMemory
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_infos,
+ addr_t reg_data_addr
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_reg_infos (reg_infos),
+ m_reg_valid (),
+ m_reg_data (),
+ m_reg_data_addr (reg_data_addr)
+{
+ // 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.
+ const size_t num_regs = reg_infos.GetNumRegisters();
+ assert (num_regs > 0);
+ m_reg_valid.resize (num_regs);
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_infos.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMemory::~RegisterContextMemory()
+{
+}
+
+void
+RegisterContextMemory::InvalidateAllRegisters ()
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ SetAllRegisterValid (false);
+}
+
+void
+RegisterContextMemory::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
+RegisterContextMemory::GetRegisterCount ()
+{
+ return m_reg_infos.GetNumRegisters ();
+}
+
+const RegisterInfo *
+RegisterContextMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_infos.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextMemory::GetRegisterSetCount ()
+{
+ return m_reg_infos.GetNumRegisterSets ();
+}
+
+const RegisterSet *
+RegisterContextMemory::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_infos.GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (!m_reg_valid[reg_num])
+ {
+ if (!ReadAllRegisterValues(m_reg_data.GetSharedDataBuffer ()))
+ return false;
+ }
+ const bool partial_data_ok = false;
+ return reg_value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok).Success();
+}
+
+bool
+RegisterContextMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
+ Error error (WriteRegisterValueToMemory(reg_info, reg_addr, reg_info->byte_size, reg_value));
+ m_reg_valid[reg_num] = false;
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::ReadAllRegisterValues (DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ {
+ SetAllRegisterValid (true);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::WriteAllRegisterValues (const DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ SetAllRegisterValid (false);
+ if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+RegisterContextMemory::SetAllRegisterData (const lldb::DataBufferSP &data_sp)
+{
+ m_reg_data.SetData(data_sp);
+ SetAllRegisterValid (true);
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.h b/source/Plugins/Process/Utility/RegisterContextMemory.h
new file mode 100644
index 000000000000..8bba52c627f3
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -0,0 +1,102 @@
+//===-- RegisterContextMemory.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_RegisterContextMemory_h_
+#define lldb_RegisterContextMemory_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+
+class DynamicRegisterInfo;
+
+class RegisterContextMemory : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMemory (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_info,
+ lldb::addr_t reg_data_addr);
+
+ virtual
+ ~RegisterContextMemory ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+
+ //------------------------------------------------------------------
+ // If all of the thread register are in a contiguous buffer in
+ // memory, then the default ReadRegister/WriteRegister and
+ // ReadAllRegisterValues/WriteAllRegisterValues will work. If thread
+ // registers are not contiguous, clients will want to subclass this
+ // class and modify the read/write functions as needed.
+ //------------------------------------------------------------------
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ void
+ SetAllRegisterData (const lldb::DataBufferSP &data_sp);
+protected:
+
+ void
+ SetAllRegisterValid (bool b);
+
+ DynamicRegisterInfo &m_reg_infos;
+ std::vector<bool> m_reg_valid;
+ lldb_private::DataExtractor m_reg_data;
+ lldb::addr_t m_reg_data_addr; // If this is valid, then we have a register context that is stored in memmory
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMemory);
+};
+
+#endif // lldb_RegisterContextMemory_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
new file mode 100644
index 000000000000..d35a5d095705
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -0,0 +1,261 @@
+//===-- RegisterContextThreadMemory.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/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr) :
+ RegisterContext (thread, 0),
+ m_thread_wp (thread.shared_from_this()),
+ m_reg_ctx_sp (),
+ m_register_data_addr (register_data_addr),
+ m_stop_id(0)
+{
+}
+
+RegisterContextThreadMemory::~RegisterContextThreadMemory()
+{
+}
+
+void
+RegisterContextThreadMemory::UpdateRegisterContext ()
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ ProcessSP process_sp (thread_sp->GetProcess());
+
+ if (process_sp)
+ {
+ const uint32_t stop_id = process_sp->GetModID().GetStopID();
+ if (m_stop_id != stop_id)
+ {
+ m_stop_id = stop_id;
+ m_reg_ctx_sp.reset();
+ }
+ if (!m_reg_ctx_sp)
+ {
+ ThreadSP backing_thread_sp (thread_sp->GetBackingThread());
+ if (backing_thread_sp)
+ {
+ m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
+ }
+ else
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os->IsOperatingSystemPluginThread (thread_sp))
+ m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS);
+ }
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+}
+
+//------------------------------------------------------------------
+// Subclasses must override these functions
+//------------------------------------------------------------------
+void
+RegisterContextThreadMemory::InvalidateAllRegisters ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ m_reg_ctx_sp->InvalidateAllRegisters();
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterCount();
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
+ return NULL;
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterSetCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSetCount();
+ return 0;
+}
+
+const RegisterSet *
+RegisterContextThreadMemory::GetRegisterSet (size_t reg_set)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSet(reg_set);
+ return NULL;
+}
+
+bool
+RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegister (reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteAllRegisterValues (data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareBreakpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareWatchpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::HardwareSingleStep (bool enable)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->HardwareSingleStep(enable);
+ return false;
+}
+
+Error
+RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
+
+Error
+RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
new file mode 100644
index 000000000000..8d7a4b622fe8
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -0,0 +1,114 @@
+//===-- RegisterContextThreadMemory.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_RegisterContextThreadMemory_h_
+#define lldb_RegisterContextThreadMemory_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextThreadMemory : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr);
+
+ virtual ~RegisterContextThreadMemory();
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value);
+
+ // These two functions are used to implement "push" and "pop" of register states. They are used primarily
+ // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
+ // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
+ // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which
+ // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation,
+ // so these API's should only be used when this behavior is needed.
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ bool
+ CopyFromRegisterContext (lldb::RegisterContextSP context);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ 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);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value);
+
+protected:
+ void
+ UpdateRegisterContext ();
+
+ lldb::ThreadWP m_thread_wp;
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ lldb::addr_t m_register_data_addr;
+ uint32_t m_stop_id;
+private:
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextThreadMemory);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextThreadMemory_h_
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp
new file mode 100644
index 000000000000..51d2052e1931
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -0,0 +1,482 @@
+//===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StopInfoMachException.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+StopInfoMachException::GetDescription ()
+{
+ if (m_description.empty() && m_value != 0)
+ {
+ ExecutionContext exe_ctx (m_thread_wp.lock());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ const char *exc_desc = NULL;
+ const char *code_label = "code";
+ const char *code_desc = NULL;
+ const char *subcode_label = "subcode";
+ const char *subcode_desc = NULL;
+ switch (m_value)
+ {
+ case 1: // EXC_BAD_ACCESS
+ exc_desc = "EXC_BAD_ACCESS";
+ subcode_label = "address";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 0xd: code_desc = "EXC_I386_GPFLT"; m_exc_data_count = 1; break;
+ }
+ break;
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break;
+ case 0x102: code_desc = "EXC_PPC_BADSPACE"; break;
+ case 0x103: code_desc = "EXC_PPC_UNALIGNED"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ exc_desc = "EXC_BAD_INSTRUCTION";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (m_exc_code == 1)
+ code_desc = "EXC_I386_INVOP";
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break;
+ case 2: code_desc = "EXC_PPC_UNIPL_INST"; break;
+ case 3: code_desc = "EXC_PPC_PRIVINST"; break;
+ case 4: code_desc = "EXC_PPC_PRIVREG"; break;
+ case 5: code_desc = "EXC_PPC_TRACE"; break;
+ case 6: code_desc = "EXC_PPC_PERFMON"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ if (m_exc_code == 1)
+ code_desc = "EXC_ARM_UNDEFINED";
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ exc_desc = "EXC_ARITHMETIC";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_DIV"; break;
+ case 2: code_desc = "EXC_I386_INTO"; break;
+ case 3: code_desc = "EXC_I386_NOEXT"; break;
+ case 4: code_desc = "EXC_I386_EXTOVR"; break;
+ case 5: code_desc = "EXC_I386_EXTERR"; break;
+ case 6: code_desc = "EXC_I386_EMERR"; break;
+ case 7: code_desc = "EXC_I386_BOUND"; break;
+ case 8: code_desc = "EXC_I386_SSEEXTERR"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_OVERFLOW"; break;
+ case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break;
+ case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break;
+ case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break;
+ case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break;
+ case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break;
+ case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4: // EXC_EMULATION
+ exc_desc = "EXC_EMULATION";
+ break;
+
+
+ case 5: // EXC_SOFTWARE
+ exc_desc = "EXC_SOFTWARE";
+ if (m_exc_code == 0x10003)
+ {
+ subcode_desc = "EXC_SOFT_SIGNAL";
+ subcode_label = "signo";
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ exc_desc = "EXC_BREAKPOINT";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_SGL"; break;
+ case 2: code_desc = "EXC_I386_BPT"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_BREAKPOINT"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ case 1: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ // FIXME temporary workaround, exc_code 0 does not really mean EXC_ARM_BREAKPOINT
+ case 0: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 7:
+ exc_desc = "EXC_SYSCALL";
+ break;
+
+ case 8:
+ exc_desc = "EXC_MACH_SYSCALL";
+ break;
+
+ case 9:
+ exc_desc = "EXC_RPC_ALERT";
+ break;
+
+ case 10:
+ exc_desc = "EXC_CRASH";
+ break;
+ case 11:
+ exc_desc = "EXC_RESOURCE";
+ break;
+ case 12:
+ exc_desc = "EXC_GUARD";
+ break;
+ }
+
+ StreamString strm;
+
+ if (exc_desc)
+ strm.PutCString(exc_desc);
+ else
+ strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
+
+ if (m_exc_data_count >= 1)
+ {
+ if (code_desc)
+ strm.Printf(" (%s=%s", code_label, code_desc);
+ else
+ strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
+ }
+
+ if (m_exc_data_count >= 2)
+ {
+ if (subcode_desc)
+ strm.Printf(", %s=%s", subcode_label, subcode_desc);
+ else
+ strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
+ }
+
+ if (m_exc_data_count > 0)
+ strm.PutChar(')');
+
+ m_description.swap (strm.GetString());
+ }
+ return m_description.c_str();
+}
+
+
+
+
+
+StopInfoSP
+StopInfoMachException::CreateStopReasonWithMachException
+(
+ Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted,
+ bool adjust_pc_if_needed
+)
+{
+ if (exc_type != 0)
+ {
+ uint32_t pc_decrement = 0;
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ switch (exc_type)
+ {
+ case 1: // EXC_BAD_ACCESS
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ switch (cpu)
+ {
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (exc_code)
+ {
+ case 1: // EXC_PPC_INVALID_SYSCALL
+ case 2: // EXC_PPC_UNIPL_INST
+ case 3: // EXC_PPC_PRIVINST
+ case 4: // EXC_PPC_PRIVREG
+ break;
+ case 5: // EXC_PPC_TRACE
+ return StopInfo::CreateStopReasonToTrace (thread);
+ case 6: // EXC_PPC_PERFMON
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ case 4: // EXC_EMULATION
+ break;
+
+ case 5: // EXC_SOFTWARE
+ if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
+ {
+ if (exc_sub_code == 5)
+ {
+ // On MacOSX, a SIGTRAP can signify that a process has called
+ // exec, so we should check with our dynamic loader to verify.
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
+ if (dynamic_loader && dynamic_loader->ProcessDidExec())
+ {
+ // The program was re-exec'ed
+ return StopInfo::CreateStopReasonWithExec (thread);
+ }
+// if (!process_did_exec)
+// {
+// // We have a SIGTRAP, make sure we didn't exec by checking
+// // for the PC being at "_dyld_start"...
+// lldb::StackFrameSP frame_sp (thread.GetStackFrameAtIndex(0));
+// if (frame_sp)
+// {
+// const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
+// if (symbol)
+// {
+// if (symbol->GetName() == ConstString("_dyld_start"))
+// process_did_exec = true;
+// }
+// }
+// }
+ }
+ }
+ return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code);
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ bool is_actual_breakpoint = false;
+ bool is_trace_if_actual_breakpoint_missing = false;
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (exc_code == 1) // EXC_I386_SGL
+ {
+ if (!exc_sub_code)
+ return StopInfo::CreateStopReasonToTrace(thread);
+
+ // It's a watchpoint, then.
+ // The exc_sub_code indicates the data break address.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ }
+ else if (exc_code == 2 || // EXC_I386_BPT
+ exc_code == 3) // EXC_I386_BPTFLT
+ {
+ // KDP returns EXC_I386_BPTFLT for trace breakpoints
+ if (exc_code == 3)
+ is_trace_if_actual_breakpoint_missing = true;
+
+ is_actual_breakpoint = true;
+ if (!pc_already_adjusted)
+ pc_decrement = 1;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
+ break;
+
+ case llvm::Triple::arm:
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled
+ // data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS
+ if (thread.GetTemporaryResumeState() == eStateStepping)
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ else if (exc_code == 1) // EXC_ARM_BREAKPOINT
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel is currently returning this so accept it as indicating a breakpoint until the kernel is fixed
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (is_actual_breakpoint)
+ {
+ RegisterContextSP reg_ctx_sp (thread.GetRegisterContext());
+ addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
+
+ ProcessSP process_sp (thread.CalculateProcess());
+
+ lldb::BreakpointSiteSP bp_site_sp;
+ if (process_sp)
+ bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // Update the PC if we were asked to do so, but only do
+ // so if we find a breakpoint that we know about cause
+ // this could be a trap instruction in the code
+ if (pc_decrement > 0 && adjust_pc_if_needed)
+ reg_ctx_sp->SetPC (pc);
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (&thread))
+ return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID());
+ else
+ return StopInfoSP();
+ }
+
+ // Don't call this a trace if we weren't single stepping this thread.
+ if (is_trace_if_actual_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping)
+ {
+ return StopInfo::CreateStopReasonToTrace (thread);
+ }
+ }
+ }
+ break;
+
+ case 7: // EXC_SYSCALL
+ case 8: // EXC_MACH_SYSCALL
+ case 9: // EXC_RPC_ALERT
+ case 10: // EXC_CRASH
+ break;
+ }
+
+ return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code));
+ }
+ return StopInfoSP();
+}
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.h b/source/Plugins/Process/Utility/StopInfoMachException.h
new file mode 100644
index 000000000000..130ee0b709b0
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -0,0 +1,77 @@
+//===-- StopInfoMachException.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_StopInfoMachException_h_
+#define liblldb_StopInfoMachException_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+namespace lldb_private {
+
+class StopInfoMachException : public StopInfo
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StopInfoMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_subcode) :
+ StopInfo (thread, exc_type),
+ m_exc_data_count (exc_data_count),
+ m_exc_code (exc_code),
+ m_exc_subcode (exc_subcode)
+ {
+ }
+
+ virtual ~StopInfoMachException()
+ {
+ }
+
+
+ virtual lldb::StopReason
+ GetStopReason () const
+ {
+ return lldb::eStopReasonException;
+ }
+
+ virtual const char *
+ GetDescription ();
+
+ // Since some mach exceptions will be reported as breakpoints, signals,
+ // or trace, we use this static accessor which will translate the mach
+ // exception into the correct StopInfo.
+ static lldb::StopInfoSP
+ CreateStopReasonWithMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted = true,
+ bool adjust_pc_if_needed = false);
+
+protected:
+ uint32_t m_exc_data_count;
+ uint64_t m_exc_code;
+ uint64_t m_exc_subcode;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_StopInfoMachException_h_
diff --git a/source/Plugins/Process/Utility/ThreadMemory.cpp b/source/Plugins/Process/Utility/ThreadMemory.cpp
new file mode 100644
index 000000000000..56e5a9a59fab
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -0,0 +1,140 @@
+//===-- ThreadMemory.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/ThreadMemory.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadMemory::ThreadMemory (Process &process,
+ tid_t tid,
+ const ValueObjectSP &thread_info_valobj_sp) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (thread_info_valobj_sp),
+ m_name(),
+ m_queue()
+{
+}
+
+
+ThreadMemory::ThreadMemory (Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (),
+ m_name(),
+ m_queue(),
+ m_register_data_addr (register_data_addr)
+{
+ if (name)
+ m_name = name;
+ if (queue)
+ m_queue = queue;
+}
+
+
+ThreadMemory::~ThreadMemory()
+{
+ DestroyThread();
+}
+
+void
+ThreadMemory::WillResume (StateType resume_state)
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->WillResume(resume_state);
+}
+
+void
+ThreadMemory::ClearStackFrames ()
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->ClearStackFrames();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadMemory::GetRegisterContext ()
+{
+ if (!m_reg_context_sp)
+ m_reg_context_sp.reset (new RegisterContextThreadMemory (*this, m_register_data_addr));
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMemory::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ reg_ctx_sp = GetRegisterContext ();
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadMemory::CalculateStopInfo ()
+{
+ if (m_backing_thread_sp)
+ {
+ lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopInfo());
+ if (backing_stop_info_sp)
+ {
+ backing_stop_info_sp->SetThread (shared_from_this());
+ SetStopInfo (backing_stop_info_sp);
+ return true;
+ }
+ }
+ else
+ {
+ ProcessSP process_sp (GetProcess());
+
+ if (process_sp)
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os)
+ {
+ SetStopInfo (os->CreateThreadStopReason (this));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+ThreadMemory::RefreshStateAfterStop()
+{
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->RefreshStateAfterStop();
+
+ if (m_reg_context_sp)
+ m_reg_context_sp->InvalidateAllRegisters();
+}
diff --git a/source/Plugins/Process/Utility/ThreadMemory.h b/source/Plugins/Process/Utility/ThreadMemory.h
new file mode 100644
index 000000000000..07eb45dcb431
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.h
@@ -0,0 +1,152 @@
+//===-- ThreadMemory.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_ThreadMemory_h_
+#define liblldb_ThreadMemory_h_
+
+#include "lldb/Target/Thread.h"
+
+class ThreadMemory :
+ public lldb_private::Thread
+{