[Lldb-commits] [lldb] r222474 - [ProcessWindows] Implement a RegisterContextWindows for x86.
Zachary Turner
zturner at google.com
Thu Nov 20 14:47:33 PST 2014
Author: zturner
Date: Thu Nov 20 16:47:32 2014
New Revision: 222474
URL: http://llvm.org/viewvc/llvm-project?rev=222474&view=rev
Log:
[ProcessWindows] Implement a RegisterContextWindows for x86.
This implements the skeleton of a RegisterContext for Windows.
In particular, this implements support only for x86 general purpose
registers.
After this patch, LLDB on Windows can perform basic debugging
operations in a single-threaded inferior process (breakpoint,
register inspection, frame select, unwinding, etc).
Differential Revision: http://reviews.llvm.org/D6322
Reviewed by: Greg Clayton
Added:
lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp
lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h
Modified:
lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt
lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp
lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp
lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h
Modified: lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt?rev=222474&r1=222473&r2=222474&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt Thu Nov 20 16:47:32 2014
@@ -7,6 +7,7 @@ add_lldb_library(lldbPluginProcessWindow
DebuggerThread.cpp
LocalDebugDelegate.cpp
ProcessWindows.cpp
+ RegisterContextWindows_x86.cpp
TargetThreadWindows.cpp
)
Modified: lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp?rev=222474&r1=222473&r2=222474&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp Thu Nov 20 16:47:32 2014
@@ -254,6 +254,7 @@ ProcessWindows::DoDestroy()
void
ProcessWindows::RefreshStateAfterStop()
{
+ m_thread_list.RefreshStateAfterStop();
}
bool
Added: lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp?rev=222474&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp Thu Nov 20 16:47:32 2014
@@ -0,0 +1,318 @@
+//===-- RegisterContextWindows_x86.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private-types.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "lldb-x86-register-enums.h"
+#include "RegisterContext_x86.h"
+#include "RegisterContextWindows_x86.h"
+#include "TargetThreadWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define DEFINE_GPR32(reg, offset, generic_reg) \
+ { \
+ #reg, nullptr, 4, offset, eEncodingUint, eFormatHexUppercase, \
+ {gcc_##reg##_i386, dwarf_##reg##_i386, generic_reg, gdb_##reg##_i386, gpr_##reg##_i386 }, nullptr, nullptr \
+ }
+
+#define GPR_REGNUM(reg) gpr_##reg##_i386
+
+// For now we're only supporting general purpose registers. Unfortunately we have to maintain
+// parallel arrays since that's how the RegisterContext interface expects things to be returned.
+// We might be able to fix this by initializing these arrays at runtime during the construction of
+// the RegisterContext by using helper functions that can update multiple arrays, register sets,
+// etc all at once through a more easily understandable interface.
+
+RegisterInfo g_register_infos[] = {DEFINE_GPR32(eax, offsetof(CONTEXT, Eax), LLDB_INVALID_REGNUM),
+ DEFINE_GPR32(ebx, offsetof(CONTEXT, Ebx), LLDB_INVALID_REGNUM),
+ DEFINE_GPR32(ecx, offsetof(CONTEXT, Ecx), LLDB_INVALID_REGNUM),
+ DEFINE_GPR32(edx, offsetof(CONTEXT, Edx), LLDB_INVALID_REGNUM),
+ DEFINE_GPR32(edi, offsetof(CONTEXT, Edi), LLDB_INVALID_REGNUM),
+ DEFINE_GPR32(esi, offsetof(CONTEXT, Esi), LLDB_INVALID_REGNUM),
+ DEFINE_GPR32(ebp, offsetof(CONTEXT, Ebp), LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR32(esp, offsetof(CONTEXT, Esp), LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR32(eip, offsetof(CONTEXT, Eip), LLDB_REGNUM_GENERIC_PC),
+ DEFINE_GPR32(eflags, offsetof(CONTEXT, EFlags), LLDB_REGNUM_GENERIC_FLAGS)};
+
+uint32_t g_gpr_regnums[] = {
+ GPR_REGNUM(eax), GPR_REGNUM(ebx), GPR_REGNUM(ecx), GPR_REGNUM(edx), GPR_REGNUM(edi),
+ GPR_REGNUM(esi), GPR_REGNUM(ebp), GPR_REGNUM(esp), GPR_REGNUM(eip), GPR_REGNUM(eflags),
+};
+
+RegisterSet g_register_sets[] = {{"General Purpose Registers", "gpr", llvm::array_lengthof(g_register_infos), g_gpr_regnums}};
+
+//------------------------------------------------------------------
+// Constructors and Destructors
+//------------------------------------------------------------------
+RegisterContextWindows_x86::RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx)
+ , m_context_valid(false)
+ , m_cached_context(new DataBufferHeap(sizeof(CONTEXT), 0))
+{
+}
+
+RegisterContextWindows_x86::~RegisterContextWindows_x86()
+{
+}
+
+void
+RegisterContextWindows_x86::InvalidateAllRegisters()
+{
+ m_context_valid = false;
+}
+
+size_t
+RegisterContextWindows_x86::GetRegisterCount()
+{
+ return llvm::array_lengthof(g_register_infos);
+}
+
+const RegisterInfo *
+RegisterContextWindows_x86::GetRegisterInfoAtIndex(size_t reg)
+{
+ return &g_register_infos[reg];
+}
+
+size_t
+RegisterContextWindows_x86::GetRegisterSetCount()
+{
+ return llvm::array_lengthof(g_register_sets);
+}
+
+const RegisterSet *
+RegisterContextWindows_x86::GetRegisterSet(size_t reg_set)
+{
+ return &g_register_sets[reg_set];
+}
+
+bool
+RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value)
+{
+ // For now we're reading the value of every register, and then returning the one that was
+ // requested. We should be smarter about this in the future.
+ if (!CacheAllRegisterValues())
+ return false;
+
+ CONTEXT *context = GetSystemContext();
+ switch (reg_info->kinds[eRegisterKindLLDB])
+ {
+ case gpr_eax_i386:
+ reg_value.SetUInt32(context->Eax);
+ break;
+ case gpr_ebx_i386:
+ reg_value.SetUInt32(context->Ebx);
+ break;
+ case gpr_ecx_i386:
+ reg_value.SetUInt32(context->Ecx);
+ break;
+ case gpr_edx_i386:
+ reg_value.SetUInt32(context->Edx);
+ break;
+ case gpr_edi_i386:
+ reg_value.SetUInt32(context->Edi);
+ break;
+ case gpr_esi_i386:
+ reg_value.SetUInt32(context->Esi);
+ break;
+ case gpr_ebp_i386:
+ reg_value.SetUInt32(context->Ebp);
+ break;
+ case gpr_esp_i386:
+ reg_value.SetUInt32(context->Esp);
+ break;
+ case gpr_eip_i386:
+ reg_value.SetUInt32(context->Eip);
+ break;
+ case gpr_eflags_i386:
+ reg_value.SetUInt32(context->EFlags);
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value)
+{
+ // Since we cannot only write a single register value to the inferior, we need to make sure
+ // our cached copy of the register values are fresh. Otherwise when writing EAX, for example,
+ // we may also overwrite some other register with a stale value.
+ if (!CacheAllRegisterValues())
+ return false;
+
+ CONTEXT *context = GetSystemContext();
+ switch (reg_info->kinds[eRegisterKindLLDB])
+ {
+ case gpr_eax_i386:
+ context->Eax = reg_value.GetAsUInt32();
+ break;
+ case gpr_ebx_i386:
+ context->Ebx = reg_value.GetAsUInt32();
+ break;
+ case gpr_ecx_i386:
+ context->Ecx = reg_value.GetAsUInt32();
+ break;
+ case gpr_edx_i386:
+ context->Edx = reg_value.GetAsUInt32();
+ break;
+ case gpr_edi_i386:
+ context->Edi = reg_value.GetAsUInt32();
+ break;
+ case gpr_esi_i386:
+ context->Esi = reg_value.GetAsUInt32();
+ break;
+ case gpr_ebp_i386:
+ context->Ebp = reg_value.GetAsUInt32();
+ break;
+ case gpr_esp_i386:
+ context->Esp = reg_value.GetAsUInt32();
+ break;
+ case gpr_eip_i386:
+ context->Eip = reg_value.GetAsUInt32();
+ break;
+ case gpr_eflags_i386:
+ context->EFlags = reg_value.GetAsUInt32();
+ break;
+ }
+
+ // Physically update the registers in the target process.
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context);
+}
+
+bool
+RegisterContextWindows_x86::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ if (!CacheAllRegisterValues())
+ return false;
+
+ if (data_sp->GetByteSize() != m_cached_context->GetByteSize())
+ return false;
+
+ // Write the OS's internal CONTEXT structure into the buffer.
+ memcpy(data_sp->GetBytes(), m_cached_context->GetBytes(), data_sp->GetByteSize());
+ return true;
+}
+
+bool
+RegisterContextWindows_x86::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ // Since we're given every register value in the input buffer, we don't need to worry about
+ // making sure our cached copy is valid and then overwriting the modified values before we
+ // push the full update to the OS. We do however need to update the cached copy with the value
+ // that we're pushing to the OS.
+ if (data_sp->GetByteSize() != m_cached_context->GetByteSize())
+ return false;
+
+ CONTEXT *context = GetSystemContext();
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+
+ if (!::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context))
+ return false;
+
+ // Since the thread context was set successfully, update our cached copy.
+ memcpy(m_cached_context->GetBytes(), data_sp->GetBytes(), data_sp->GetByteSize());
+ return true;
+}
+
+uint32_t
+RegisterContextWindows_x86::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert(kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+//------------------------------------------------------------------
+// Subclasses can these functions if desired
+//------------------------------------------------------------------
+uint32_t
+RegisterContextWindows_x86::NumSupportedHardwareBreakpoints()
+{
+ // Support for hardware breakpoints not yet implemented.
+ return 0;
+}
+
+uint32_t
+RegisterContextWindows_x86::SetHardwareBreakpoint(lldb::addr_t addr, size_t size)
+{
+ return 0;
+}
+
+bool
+RegisterContextWindows_x86::ClearHardwareBreakpoint(uint32_t hw_idx)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextWindows_x86::NumSupportedHardwareWatchpoints()
+{
+ // Support for hardware watchpoints not yet implemented.
+ return 0;
+}
+
+uint32_t
+RegisterContextWindows_x86::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ return 0;
+}
+
+bool
+RegisterContextWindows_x86::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextWindows_x86::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+CONTEXT *
+RegisterContextWindows_x86::GetSystemContext()
+{
+ return reinterpret_cast<CONTEXT *>(m_cached_context->GetBytes());
+}
+
+bool
+RegisterContextWindows_x86::CacheAllRegisterValues()
+{
+ if (m_context_valid)
+ return true;
+
+ CONTEXT *context = GetSystemContext();
+ // Right now we just pull every single register, regardless of what register we're ultimately
+ // going to read. We could be smarter about this, although it's not clear what the advantage
+ // would be.
+ context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context))
+ return false;
+ m_context_valid = true;
+ return true;
+}
Added: lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h?rev=222474&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h (added)
+++ lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h Thu Nov 20 16:47:32 2014
@@ -0,0 +1,81 @@
+//===-- RegisterContextWindows_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_RegisterContextWindows_x86_H_
+#define liblldb_RegisterContextWindows_x86_H_
+
+#include "lldb/lldb-forward.h"
+#include "lldb/Target/RegisterContext.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindows_x86 : public lldb_private::RegisterContext
+{
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual ~RegisterContextWindows_x86();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ bool ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) override;
+
+ bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) override;
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ uint32_t NumSupportedHardwareBreakpoints() override;
+
+ uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
+
+ uint32_t NumSupportedHardwareWatchpoints() override;
+
+ uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) override;
+
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+ private:
+ CONTEXT *GetSystemContext();
+
+ bool CacheAllRegisterValues();
+
+ lldb::DataBufferSP m_cached_context;
+ bool m_context_valid;
+};
+}
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_x86_H_
Modified: lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp?rev=222474&r1=222473&r2=222474&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp Thu Nov 20 16:47:32 2014
@@ -7,11 +7,16 @@
//
//===----------------------------------------------------------------------===//
-#include "TargetThreadWindows.h"
-#include "ProcessWindows.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/HostNativeThreadBase.h"
#include "lldb/Host/windows/HostThreadWindows.h"
#include "lldb/Host/windows/windows.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "TargetThreadWindows.h"
+#include "ProcessWindows.h"
+#include "RegisterContextWindows_x86.h"
+#include "UnwindLLDB.h"
using namespace lldb;
using namespace lldb_private;
@@ -30,6 +35,7 @@ TargetThreadWindows::~TargetThreadWindow
void
TargetThreadWindows::RefreshStateAfterStop()
{
+ GetRegisterContext()->InvalidateIfNeeded(false);
}
void
@@ -45,19 +51,51 @@ TargetThreadWindows::DidStop()
RegisterContextSP
TargetThreadWindows::GetRegisterContext()
{
- return RegisterContextSP();
+ if (!m_reg_context_sp)
+ m_reg_context_sp = CreateRegisterContextForFrameIndex(0);
+
+ return m_reg_context_sp;
}
RegisterContextSP
TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame)
{
- return RegisterContextSP();
+ return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex());
+}
+
+RegisterContextSP
+TargetThreadWindows::CreateRegisterContextForFrameIndex(uint32_t idx)
+{
+ if (!m_reg_context_sp)
+ {
+ ArchSpec arch = HostInfo::GetArchitecture();
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ m_reg_context_sp.reset(new RegisterContextWindows_x86(*this, idx));
+ break;
+ default:
+ // FIXME: Support x64 by creating a RegisterContextWindows_x86_64
+ break;
+ }
+ }
+ return m_reg_context_sp;
}
bool
TargetThreadWindows::CalculateStopInfo()
{
- return false;
+ SetStopInfo(m_stop_info_sp);
+ return true;
+}
+
+Unwind *
+TargetThreadWindows::GetUnwinder()
+{
+ // FIXME: Implement an unwinder based on the Windows unwinder exposed through DIA SDK.
+ if (m_unwinder_ap.get() == NULL)
+ m_unwinder_ap.reset(new UnwindLLDB(*this));
+ return m_unwinder_ap.get();
}
bool
Modified: lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h?rev=222474&r1=222473&r2=222474&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h (original)
+++ lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h Thu Nov 20 16:47:32 2014
@@ -28,16 +28,26 @@ class TargetThreadWindows : public lldb_
TargetThreadWindows(ProcessWindows &process, const HostThread &thread);
virtual ~TargetThreadWindows();
- virtual void RefreshStateAfterStop() override;
- virtual void WillResume(lldb::StateType resume_state) override;
- virtual void DidStop() override;
- virtual lldb::RegisterContextSP GetRegisterContext() override;
- virtual lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) override;
- virtual bool CalculateStopInfo() override;
+ // lldb_private::Thread overrides
+ void RefreshStateAfterStop() override;
+ void WillResume(lldb::StateType resume_state) override;
+ void DidStop() override;
+ lldb::RegisterContextSP GetRegisterContext() override;
+ lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) override;
+ bool CalculateStopInfo() override;
+ Unwind *GetUnwinder() override;
bool DoResume();
+ HostThread
+ GetHostThread() const
+ {
+ return m_host_thread;
+ }
+
private:
+ lldb::RegisterContextSP CreateRegisterContextForFrameIndex(uint32_t idx);
+
lldb::StackFrameUP m_stack_frame;
HostThread m_host_thread;
More information about the lldb-commits
mailing list