summaryrefslogtreecommitdiffstats
path: root/source/Plugins/Process/POSIX
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/POSIX')
-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
20 files changed, 6001 insertions, 0 deletions
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
new file mode 100644
index 0000000..6e2c140
--- /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 0000000..cbf309e
--- /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 0000000..93c2966
--- /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 0000000..d051d23
--- /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 0000000..60a29e0
--- /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 0000000..c6c460c
--- /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 0000000..f04631d
--- /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 0000000..48b19ba
--- /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 0000000..624ca87
--- /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 0000000..a1e2e37
--- /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 0000000..0fb9dc1
--- /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 0000000..ffff40a
--- /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 0000000..c1aea2a
--- /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 0000000..1509ef5
--- /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 0000000..63ae01e
--- /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 0000000..49676bd
--- /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 0000000..96066c4
--- /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 0000000..61a25c4
--- /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 0000000..617b184
--- /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 0000000..9d59bd7
--- /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_
OpenPOWER on IntegriCloud