Index: lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt +++ lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt @@ -7,6 +7,7 @@ DebuggerThread.cpp LocalDebugDelegate.cpp ProcessWindows.cpp + RegisterContextWindows_x86.cpp TargetThreadWindows.cpp ) Index: lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp +++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp @@ -254,6 +254,7 @@ void ProcessWindows::RefreshStateAfterStop() { + m_thread_list.RefreshStateAfterStop(); } bool Index: lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h +++ lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.h @@ -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_ Index: lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp +++ lldb/trunk/source/Plugins/Process/Windows/RegisterContextWindows_x86.cpp @@ -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(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(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(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(m_thread); + if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context)) + return false; + m_context_valid = true; + return true; +} Index: lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h +++ lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.h @@ -28,16 +28,26 @@ 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; Index: lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp +++ lldb/trunk/source/Plugins/Process/Windows/TargetThreadWindows.cpp @@ -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 @@ void TargetThreadWindows::RefreshStateAfterStop() { + GetRegisterContext()->InvalidateIfNeeded(false); } void @@ -45,19 +51,51 @@ 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