Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -81,6 +81,7 @@ list(APPEND LLDB_USED_LIBS lldbPluginProcessWindows lldbPluginProcessWinMiniDump + lldbPluginProcessWindowsCommon Ws2_32 Rpcrt4 ) Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -76,7 +76,7 @@ #if defined(_MSC_VER) #include "lldb/Host/windows/windows.h" -#include "Plugins/Process/Windows/Live/ProcessWindows.h" +#include "Plugins/Process/Windows/Live/ProcessWindowsLive.h" #include "Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h" #endif @@ -307,7 +307,7 @@ ObjCPlusPlusLanguage::Initialize(); #if defined(_MSC_VER) - ProcessWindows::Initialize(); + ProcessWindowsLive::Initialize(); #endif #if defined(__FreeBSD__) ProcessFreeBSD::Initialize(); Index: source/Initialization/SystemInitializerCommon.cpp =================================================================== --- source/Initialization/SystemInitializerCommon.cpp +++ source/Initialization/SystemInitializerCommon.cpp @@ -49,7 +49,7 @@ #if defined(_MSC_VER) #include "lldb/Host/windows/windows.h" -#include "Plugins/Process/Windows/Live/ProcessWindowsLog.h" +#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" #endif #include "llvm/Support/TargetSelect.h" Index: source/Plugins/Process/CMakeLists.txt =================================================================== --- source/Plugins/Process/CMakeLists.txt +++ source/Plugins/Process/CMakeLists.txt @@ -9,6 +9,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows/Live) add_subdirectory(Windows/MiniDump) + add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_subdirectory(MacOSX-Kernel) endif() Index: source/Plugins/Process/Windows/Common/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/CMakeLists.txt @@ -0,0 +1,23 @@ +include_directories(.) +include_directories(../../Utility) + +set(PROC_WINDOWS_COMMON_SOURCES + RegisterContextWindows.cpp + ProcessWindows.cpp + ProcessWindowsLog.cpp + TargetThreadWindows.cpp + ) + +if (CMAKE_SIZEOF_VOID_P EQUAL 4) + set(PROC_WINDOWS_COMMON_SOURCES ${PROC_WINDOWS_COMMON_SOURCES} + x86/RegisterContextWindows_x86.cpp + ) +elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(PROC_WINDOWS_COMMON_SOURCES ${PROC_WINDOWS_COMMON_SOURCES} + x64/RegisterContextWindows_x64.cpp + ) +endif() + +add_lldb_library(lldbPluginProcessWindowsCommon + ${PROC_WINDOWS_COMMON_SOURCES} + ) Index: source/Plugins/Process/Windows/Common/ProcessWindows.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -0,0 +1,41 @@ +//===-- ProcessWindows.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_Plugins_Process_Windows_Common_ProcessWindows_H_ +#define liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ + +// Other libraries and framework includes +#include "lldb/lldb-forward.h" +#include "lldb/Core/Error.h" +#include "lldb/Target/Process.h" + +namespace lldb_private +{ + +class ProcessWindows : public lldb_private::Process +{ +public: + //------------------------------------------------------------------ + // Constructors and destructors + //------------------------------------------------------------------ + ProcessWindows(lldb::TargetSP target_sp, + lldb_private::Listener &listener); + + ~ProcessWindows(); + + size_t GetSTDOUT(char *buf, size_t buf_size, lldb_private::Error &error) override; + size_t GetSTDERR(char *buf, size_t buf_size, lldb_private::Error &error) override; + size_t PutSTDIN(const char *buf, size_t buf_size, lldb_private::Error &error) override; + + lldb::addr_t GetImageInfoAddress() override; +}; + +} + +#endif // liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ Index: source/Plugins/Process/Windows/Common/ProcessWindows.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -0,0 +1,77 @@ +//===-- ProcessWindows.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ProcessWindows.h" + +// Other libraries and framework includes +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/State.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +namespace lldb_private +{ + +//------------------------------------------------------------------------------ +// Constructors and destructors. + +ProcessWindows::ProcessWindows(lldb::TargetSP target_sp, Listener &listener) + : lldb_private::Process(target_sp, listener) +{ +} + +ProcessWindows::~ProcessWindows() +{ +} + +size_t +ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Error &error) +{ + error.SetErrorString("GetSTDOUT unsupported on Windows"); + return 0; +} + +size_t +ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Error &error) +{ + error.SetErrorString("GetSTDERR unsupported on Windows"); + return 0; +} + +size_t +ProcessWindows::PutSTDIN(const char *buf, size_t buf_size, Error &error) +{ + error.SetErrorString("PutSTDIN unsupported on Windows"); + return 0; +} + +//------------------------------------------------------------------------------ +// ProcessInterface protocol. + + +lldb::addr_t +ProcessWindows::GetImageInfoAddress() +{ + Target &target = GetTarget(); + ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(&target); + if (addr.IsValid()) + return addr.GetLoadAddress(&target); + else + return LLDB_INVALID_ADDRESS; +} + +} Index: source/Plugins/Process/Windows/Common/ProcessWindowsForward.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/ProcessWindowsForward.h @@ -0,0 +1,19 @@ +//===-- ProcessWindowsForward.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_Plugins_Process_Windows_ProcessWindowsForward_H_ +#define liblldb_Plugins_Process_Windows_ProcessWindowsForward_H_ + +#include + +class ProcessWindows; + +typedef std::shared_ptr ProcessWindowsSP; + +#endif \ No newline at end of file Index: source/Plugins/Process/Windows/Common/ProcessWindowsLog.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/ProcessWindowsLog.h @@ -0,0 +1,96 @@ +//===-- ProcessWindowsLog.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_ProcessWindowsLog_h_ +#define liblldb_ProcessWindowsLog_h_ + +#include "lldb/Core/Log.h" + +#define WINDOWS_LOG_VERBOSE (1u << 0) +#define WINDOWS_LOG_PROCESS (1u << 1) // Log process operations +#define WINDOWS_LOG_EXCEPTION (1u << 1) // Log exceptions +#define WINDOWS_LOG_THREAD (1u << 2) // Log thread operations +#define WINDOWS_LOG_MEMORY (1u << 3) // Log memory reads/writes calls +#define WINDOWS_LOG_BREAKPOINTS (1u << 4) // Log breakpoint operations +#define WINDOWS_LOG_STEP (1u << 5) // Log step operations +#define WINDOWS_LOG_REGISTERS (1u << 6) // Log register operations +#define WINDOWS_LOG_EVENT (1u << 7) // Low level debug events +#define WINDOWS_LOG_ALL (UINT32_MAX) + +enum class LogMaskReq +{ + All, + Any +}; + +class ProcessWindowsLog +{ + static const char *m_pluginname; + +public: + // --------------------------------------------------------------------- + // Public Static Methods + // --------------------------------------------------------------------- + static void + Initialize(); + + static void + Terminate(); + + static void + RegisterPluginName(const char *pluginName) + { + m_pluginname = pluginName; + } + + static void + RegisterPluginName(lldb_private::ConstString pluginName) + { + m_pluginname = pluginName.GetCString(); + } + + static bool + TestLogFlags(uint32_t mask, LogMaskReq req); + + static lldb_private::Log * + GetLog(); + + 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); +}; + +#define WINLOGF_IF(Flags, Req, Method, ...) \ + { \ + if (ProcessWindowsLog::TestLogFlags(Flags, Req)) \ + { \ + Log *log = ProcessWindowsLog::GetLog(); \ + if (log) \ + log->Method(__VA_ARGS__); \ + } \ + } + +#define WINLOG_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Printf, __VA_ARGS__) +#define WINLOG_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Printf, __VA_ARGS__) +#define WINLOGV_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Verbose, __VA_ARGS__) +#define WINLOGV_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Verbose, __VA_ARGS__) +#define WINLOGD_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Debug, __VA_ARGS__) +#define WINLOGD_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Debug, __VA_ARGS__) +#define WINERR_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Error, __VA_ARGS__) +#define WINERR_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Error, __VA_ARGS__) +#define WINWARN_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Warning, __VA_ARGS__) +#define WINWARN_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Warning, __VA_ARGS__) + +#endif // liblldb_ProcessWindowsLog_h_ Index: source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp @@ -0,0 +1,194 @@ +//===-- ProcessWindowsLog.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ProcessWindowsLog.h" + +#include + +#include "lldb/Core/StreamFile.h" +#include "lldb/Interpreter/Args.h" +#include "llvm/Support/ManagedStatic.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 = nullptr; + +static llvm::ManagedStatic g_once_flag; + +void +ProcessWindowsLog::Initialize() +{ + static ConstString g_name("windows"); + + std::call_once(*g_once_flag, [](){ + Log::Callbacks log_callbacks = { + DisableLog, + EnableLog, + ListLogCategories + }; + + Log::RegisterLogChannel(g_name, log_callbacks); + RegisterPluginName(g_name); + }); +} + +void +ProcessWindowsLog::Terminate() +{ +} + +Log * +ProcessWindowsLog::GetLog() +{ + return (g_log_enabled) ? g_log : nullptr; +} + +bool +ProcessWindowsLog::TestLogFlags(uint32_t mask, LogMaskReq req) +{ + Log *log = GetLog(); + if (!log) + return false; + + uint32_t log_mask = log->GetMask().Get(); + if (req == LogMaskReq::All) + return ((log_mask & mask) == mask); + else + return (log_mask & mask); +} + +static uint32_t +GetFlagBits(const char *arg) +{ + if (::strcasecmp(arg, "all") == 0 ) return WINDOWS_LOG_ALL; + else if (::strcasecmp(arg, "break") == 0 ) return WINDOWS_LOG_BREAKPOINTS; + else if (::strcasecmp(arg, "event") == 0 ) return WINDOWS_LOG_EVENT; + else if (::strcasecmp(arg, "exception") == 0 ) return WINDOWS_LOG_EXCEPTION; + else if (::strcasecmp(arg, "memory") == 0 ) return WINDOWS_LOG_MEMORY; + else if (::strcasecmp(arg, "process") == 0 ) return WINDOWS_LOG_PROCESS; + else if (::strcasecmp(arg, "registers") == 0 ) return WINDOWS_LOG_REGISTERS; + else if (::strcasecmp(arg, "step") == 0 ) return WINDOWS_LOG_STEP; + else if (::strcasecmp(arg, "thread") == 0 ) return WINDOWS_LOG_THREAD; + else if (::strcasecmp(arg, "verbose") == 0 ) return WINDOWS_LOG_VERBOSE; + return 0; +} + +void +ProcessWindowsLog::DisableLog(const char **args, Stream *feedback_strm) +{ + Log *log (GetLog()); + if (log) + { + uint32_t flag_bits = 0; + + if (args[0] != nullptr) + { + 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; + log->SetStream(lldb::StreamSP()); + } + } + + return; +} + +Log * +ProcessWindowsLog::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 = WINDOWS_LOG_ALL; + g_log->GetMask().Reset(flag_bits); + g_log->GetOptions().Reset(log_options); + g_log_enabled = true; + } + return g_log; +} + +void +ProcessWindowsLog::ListLogCategories(Stream *strm) +{ + strm->Printf("Logging categories for '%s':\n" + " all - turn on all available logging categories\n" + " break - log breakpoints\n" + " event - log low level debugger events\n" + " exception - log exception information\n" + " memory - log memory reads and writes\n" + " process - log process events and activities\n" + " registers - log register read/writes\n" + " thread - log thread events and activities\n" + " step - log step related activities\n" + " verbose - enable verbose logging\n", + ProcessWindowsLog::m_pluginname); +} + +const char *ProcessWindowsLog::m_pluginname = ""; Index: source/Plugins/Process/Windows/Common/RegisterContextWindows.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/RegisterContextWindows.h @@ -0,0 +1,69 @@ +//===-- RegisterContextWindows.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_H_ +#define liblldb_RegisterContextWindows_H_ + +#include "lldb/lldb-forward.h" +#include "lldb/Target/RegisterContext.h" + +namespace lldb_private +{ + +class Thread; + +class RegisterContextWindows : public lldb_private::RegisterContext +{ + public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + RegisterContextWindows(Thread &thread, uint32_t concrete_frame_idx); + + virtual ~RegisterContextWindows(); + + //------------------------------------------------------------------ + // Subclasses must override these functions + //------------------------------------------------------------------ + void InvalidateAllRegisters() 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; + + protected: + virtual bool CacheAllRegisterValues(); + + CONTEXT m_context; + + private: + bool m_context_stale; +}; +} + +#endif // #ifndef liblldb_RegisterContextWindows_H_ Index: source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp @@ -0,0 +1,155 @@ +//===-- RegisterContextWindows.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private-types.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/windows/HostThreadWindows.h" +#include "lldb/Host/windows/windows.h" + +#include "ProcessWindowsLog.h" +#include "RegisterContextWindows.h" +#include "TargetThreadWindows.h" + +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; +using namespace lldb_private; + +const DWORD kWinContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + +//------------------------------------------------------------------ +// Constructors and Destructors +//------------------------------------------------------------------ +RegisterContextWindows::RegisterContextWindows(Thread &thread, uint32_t concrete_frame_idx) + : RegisterContext(thread, concrete_frame_idx) + , m_context() + , m_context_stale(true) +{ +} + +RegisterContextWindows::~RegisterContextWindows() +{ +} + +void +RegisterContextWindows::InvalidateAllRegisters() +{ + m_context_stale = true; +} + +bool +RegisterContextWindows::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + if (!CacheAllRegisterValues()) + return false; + if (data_sp->GetByteSize() < sizeof(m_context)) + { + data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); + } + memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context)); + return true; +} + +bool +RegisterContextWindows::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + assert(data_sp->GetByteSize() >= sizeof(m_context)); + memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context)); + + TargetThreadWindows &wthread = static_cast(m_thread); + if (!::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context)) + return false; + + return true; +} + +uint32_t +RegisterContextWindows::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::NumSupportedHardwareBreakpoints() +{ + // Support for hardware breakpoints not yet implemented. + return 0; +} + +uint32_t +RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) +{ + return 0; +} + +bool +RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) +{ + return false; +} + +uint32_t +RegisterContextWindows::NumSupportedHardwareWatchpoints() +{ + // Support for hardware watchpoints not yet implemented. + return 0; +} + +uint32_t +RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) +{ + return 0; +} + +bool +RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextWindows::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextWindows::CacheAllRegisterValues() +{ + if (!m_context_stale) + return true; + + TargetThreadWindows &wthread = static_cast(m_thread); + memset(&m_context, 0, sizeof(m_context)); + m_context.ContextFlags = kWinContextFlags; + if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context)) + { + WINERR_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext failed with error %u while caching register values.", + ::GetLastError()); + return false; + } + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext successfully updated the register values.", ::GetLastError()); + m_context_stale = false; + return true; +} Index: source/Plugins/Process/Windows/Common/TargetThreadWindows.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/TargetThreadWindows.h @@ -0,0 +1,50 @@ +//===-- TargetThreadWindows.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_Plugins_Process_Windows_TargetThreadWindows_H_ +#define liblldb_Plugins_Process_Windows_TargetThreadWindows_H_ + +//#include "ForwardDecl.h" +#include "lldb/lldb-forward.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/Thread.h" + +namespace lldb_private +{ +class ProcessWindows; +class HostThread; +class StackFrame; + +class TargetThreadWindows : public lldb_private::Thread +{ + public: + TargetThreadWindows(ProcessWindows &process, const HostThread &thread); + virtual ~TargetThreadWindows(); + + // lldb_private::Thread overrides + void RefreshStateAfterStop() override; + void WillResume(lldb::StateType resume_state) override; + void DidStop() override; + bool CalculateStopInfo() override; + Unwind *GetUnwinder() override; + + bool DoResume(); + + HostThread + GetHostThread() const + { + return m_host_thread; + } + + private: + HostThread m_host_thread; +}; +} + +#endif Index: source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -0,0 +1,98 @@ +//===-- TargetThreadWindows.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/Log.h" +#include "lldb/Core/Logging.h" +#include "lldb/Core/State.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 "ProcessWindowsLog.h" +#include "UnwindLLDB.h" + +using namespace lldb; +using namespace lldb_private; + +TargetThreadWindows::TargetThreadWindows(ProcessWindows &process, const HostThread &thread) + : Thread(process, thread.GetNativeThread().GetThreadId()) + , m_host_thread(thread) +{ +} + +TargetThreadWindows::~TargetThreadWindows() +{ + DestroyThread(); +} + +void +TargetThreadWindows::RefreshStateAfterStop() +{ + ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle()); + SetState(eStateStopped); + GetRegisterContext()->InvalidateIfNeeded(false); +} + +void +TargetThreadWindows::WillResume(lldb::StateType resume_state) +{ +} + +void +TargetThreadWindows::DidStop() +{ +} + +bool +TargetThreadWindows::CalculateStopInfo() +{ + 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 +TargetThreadWindows::DoResume() +{ + StateType resume_state = GetTemporaryResumeState(); + StateType current_state = GetState(); + if (resume_state == current_state) + return true; + + if (resume_state == eStateStepping) + { + uint32_t flags_index = GetRegisterContext()->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + uint64_t flags_value = GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0); + flags_value |= 0x100; // Set the trap flag on the CPU + GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value); + } + + if (resume_state == eStateStepping || resume_state == eStateRunning) + { + DWORD previous_suspend_count = 0; + HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle(); + do + { + previous_suspend_count = ::ResumeThread(thread_handle); + } while (previous_suspend_count > 0); + } + return true; +} Index: source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h @@ -0,0 +1,48 @@ +//===-- RegisterContextWindows_x64.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_x64_H_ +#define liblldb_RegisterContextWindows_x64_H_ + +#include "lldb/lldb-forward.h" +#include "RegisterContextWindows.h" + +namespace lldb_private +{ + +class Thread; + +class RegisterContextWindows_x64 : public RegisterContextWindows +{ + public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + RegisterContextWindows_x64(Thread &thread, uint32_t concrete_frame_idx); + + virtual ~RegisterContextWindows_x64(); + + //------------------------------------------------------------------ + // Subclasses must override these functions + //------------------------------------------------------------------ + 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; +}; +} + +#endif // #ifndef liblldb_RegisterContextPOSIX_x64_H_ Index: source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp @@ -0,0 +1,323 @@ +//===-- RegisterContextWindows_x64.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private-types.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_x64.h" +#include "TargetThreadWindows.h" + +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; +using namespace lldb_private; + +#define DEFINE_GPR(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatHexUppercase +#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatBinary + +namespace +{ + +// This enum defines the layout of the global RegisterInfo array. This is necessary because +// lldb register sets are defined in terms of indices into the register array. As such, the +// order of RegisterInfos defined in global registers array must match the order defined here. +// When defining the register set layouts, these values can appear in an arbitrary order, and that +// determines the order that register values are displayed in a dump. +enum RegisterIndex +{ + eRegisterIndexRax, + eRegisterIndexRbx, + eRegisterIndexRcx, + eRegisterIndexRdx, + eRegisterIndexRdi, + eRegisterIndexRsi, + eRegisterIndexR8, + eRegisterIndexR9, + eRegisterIndexR10, + eRegisterIndexR11, + eRegisterIndexR12, + eRegisterIndexR13, + eRegisterIndexR14, + eRegisterIndexR15, + eRegisterIndexRbp, + eRegisterIndexRsp, + eRegisterIndexRip, + eRegisterIndexRflags +}; + +// Array of all register information supported by Windows x86 +RegisterInfo g_register_infos[] = { + // Macro auto defines most stuff eh_frame DWARF GENERIC + // GDB LLDB VALUE REGS INVALIDATE REGS + // ================================ ========================= ====================== ========================= + // =================== ================= ========== =============== + {DEFINE_GPR(rax, nullptr), + {dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rax_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rbx, nullptr), + {dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rbx_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rcx, nullptr), + {dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rcx_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rdx, nullptr), + {dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rdx_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rdi, nullptr), + {dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rdi_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rsi, nullptr), + {dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rsi_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r8, nullptr), + {dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r8_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r9, nullptr), + {dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r9_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r10, nullptr), + {dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r10_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r11, nullptr), + {dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r11_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r12, nullptr), + {dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r12_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r13, nullptr), + {dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r13_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r14, nullptr), + {dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r14_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(r15, nullptr), + {dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r15_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rbp, "fp"), + {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, lldb_rbp_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rsp, "sp"), + {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, lldb_rsp_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rip, "pc"), + {dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, lldb_rip_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR_BIN(eflags, "flags"), + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, lldb_rflags_x86_64}, + nullptr, + nullptr}, +}; + +// Array of lldb register numbers used to define the set of all General Purpose Registers +uint32_t g_gpr_reg_indices[] = {eRegisterIndexRax, eRegisterIndexRbx, eRegisterIndexRcx, eRegisterIndexRdx, + eRegisterIndexRdi, eRegisterIndexRsi, eRegisterIndexR8, eRegisterIndexR9, + eRegisterIndexR10, eRegisterIndexR11, eRegisterIndexR12, eRegisterIndexR13, + eRegisterIndexR14, eRegisterIndexR15, eRegisterIndexRbp, eRegisterIndexRsp, + eRegisterIndexRip, eRegisterIndexRflags}; + +RegisterSet g_register_sets[] = { + {"General Purpose Registers", "gpr", llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices}, +}; +} + +//------------------------------------------------------------------ +// Constructors and Destructors +//------------------------------------------------------------------ +RegisterContextWindows_x64::RegisterContextWindows_x64(Thread &thread, uint32_t concrete_frame_idx) + : RegisterContextWindows(thread, concrete_frame_idx) +{ +} + +RegisterContextWindows_x64::~RegisterContextWindows_x64() +{ +} + +size_t +RegisterContextWindows_x64::GetRegisterCount() +{ + return llvm::array_lengthof(g_register_infos); +} + +const RegisterInfo * +RegisterContextWindows_x64::GetRegisterInfoAtIndex(size_t reg) +{ + return &g_register_infos[reg]; +} + +size_t +RegisterContextWindows_x64::GetRegisterSetCount() +{ + return llvm::array_lengthof(g_register_sets); +} + +const RegisterSet * +RegisterContextWindows_x64::GetRegisterSet(size_t reg_set) +{ + return &g_register_sets[reg_set]; +} + +bool +RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) +{ + if (!CacheAllRegisterValues()) + return false; + + switch (reg_info->kinds[eRegisterKindLLDB]) + { + case lldb_rax_x86_64: + reg_value.SetUInt64(m_context.Rax); + break; + case lldb_rbx_x86_64: + reg_value.SetUInt64(m_context.Rbx); + break; + case lldb_rcx_x86_64: + reg_value.SetUInt64(m_context.Rcx); + break; + case lldb_rdx_x86_64: + reg_value.SetUInt64(m_context.Rdx); + break; + case lldb_rdi_x86_64: + reg_value.SetUInt64(m_context.Rdi); + break; + case lldb_rsi_x86_64: + reg_value.SetUInt64(m_context.Rsi); + break; + case lldb_r8_x86_64: + reg_value.SetUInt64(m_context.R8); + break; + case lldb_r9_x86_64: + reg_value.SetUInt64(m_context.R9); + break; + case lldb_r10_x86_64: + reg_value.SetUInt64(m_context.R10); + break; + case lldb_r11_x86_64: + reg_value.SetUInt64(m_context.R11); + break; + case lldb_r12_x86_64: + reg_value.SetUInt64(m_context.R12); + break; + case lldb_r13_x86_64: + reg_value.SetUInt64(m_context.R13); + break; + case lldb_r14_x86_64: + reg_value.SetUInt64(m_context.R14); + break; + case lldb_r15_x86_64: + reg_value.SetUInt64(m_context.R15); + break; + case lldb_rbp_x86_64: + reg_value.SetUInt64(m_context.Rbp); + break; + case lldb_rsp_x86_64: + reg_value.SetUInt64(m_context.Rsp); + break; + case lldb_rip_x86_64: + reg_value.SetUInt64(m_context.Rip); + break; + case lldb_rflags_x86_64: + reg_value.SetUInt64(m_context.EFlags); + break; + } + return true; +} + +bool +RegisterContextWindows_x64::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; + + switch (reg_info->kinds[eRegisterKindLLDB]) + { + case lldb_rax_x86_64: + m_context.Rax = reg_value.GetAsUInt64(); + break; + case lldb_rbx_x86_64: + m_context.Rbx = reg_value.GetAsUInt64(); + break; + case lldb_rcx_x86_64: + m_context.Rcx = reg_value.GetAsUInt64(); + break; + case lldb_rdx_x86_64: + m_context.Rdx = reg_value.GetAsUInt64(); + break; + case lldb_rdi_x86_64: + m_context.Rdi = reg_value.GetAsUInt64(); + break; + case lldb_rsi_x86_64: + m_context.Rsi = reg_value.GetAsUInt64(); + break; + case lldb_r8_x86_64: + m_context.R8 = reg_value.GetAsUInt64(); + break; + case lldb_r9_x86_64: + m_context.R9 = reg_value.GetAsUInt64(); + break; + case lldb_r10_x86_64: + m_context.R10 = reg_value.GetAsUInt64(); + break; + case lldb_r11_x86_64: + m_context.R11 = reg_value.GetAsUInt64(); + break; + case lldb_r12_x86_64: + m_context.R12 = reg_value.GetAsUInt64(); + break; + case lldb_r13_x86_64: + m_context.R13 = reg_value.GetAsUInt64(); + break; + case lldb_r14_x86_64: + m_context.R14 = reg_value.GetAsUInt64(); + break; + case lldb_r15_x86_64: + m_context.R15 = reg_value.GetAsUInt64(); + break; + case lldb_rbp_x86_64: + m_context.Rbp = reg_value.GetAsUInt64(); + break; + case lldb_rsp_x86_64: + m_context.Rsp = reg_value.GetAsUInt64(); + break; + case lldb_rip_x86_64: + m_context.Rip = reg_value.GetAsUInt64(); + break; + case lldb_rflags_x86_64: + m_context.EFlags = reg_value.GetAsUInt64(); + break; + } + + // Physically update the registers in the target process. + TargetThreadWindows &wthread = static_cast(m_thread); + return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); +} Index: source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h @@ -0,0 +1,45 @@ +//===-- 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 "RegisterContextWindows.h" + +namespace lldb_private +{ + +class Thread; + +class RegisterContextWindows_x86 : public RegisterContextWindows +{ + public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx); + + virtual ~RegisterContextWindows_x86(); + + //------------------------------------------------------------------ + // Subclasses must override these functions + //------------------------------------------------------------------ + size_t GetRegisterCount() override; + + const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + + size_t GetRegisterSetCount() override; + + const RegisterSet *GetRegisterSet(size_t reg_set) override; +}; + +} + +#endif // #ifndef liblldb_RegisterContextWindows_x86_H_ Index: source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp @@ -0,0 +1,123 @@ +//===-- RegisterContextWindows_x86.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private-types.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 "ProcessWindowsLog.h" +#include "RegisterContext_x86.h" +#include "RegisterContextWindows_x86.h" + +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; +using namespace lldb_private; + +#define DEFINE_GPR(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatHexUppercase +#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatBinary + +namespace +{ + +// This enum defines the layout of the global RegisterInfo array. This is necessary because +// lldb register sets are defined in terms of indices into the register array. As such, the +// order of RegisterInfos defined in global registers array must match the order defined here. +// When defining the register set layouts, these values can appear in an arbitrary order, and that +// determines the order that register values are displayed in a dump. +enum RegisterIndex +{ + eRegisterIndexEax, + eRegisterIndexEbx, + eRegisterIndexEcx, + eRegisterIndexEdx, + eRegisterIndexEdi, + eRegisterIndexEsi, + eRegisterIndexEbp, + eRegisterIndexEsp, + eRegisterIndexEip, + eRegisterIndexEflags +}; + +// Array of all register information supported by Windows x86 +RegisterInfo g_register_infos[] = +{ +// Macro auto defines most stuff eh_frame DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS +// ============================== ======================= =================== ========================= =================== ================= ========== =============== + { DEFINE_GPR(eax, nullptr), { ehframe_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_eax_i386 }, nullptr, nullptr}, + { DEFINE_GPR(ebx, nullptr), { ehframe_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_ebx_i386 }, nullptr, nullptr}, + { DEFINE_GPR(ecx, nullptr), { ehframe_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_ecx_i386 }, nullptr, nullptr}, + { DEFINE_GPR(edx, nullptr), { ehframe_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_edx_i386 }, nullptr, nullptr}, + { DEFINE_GPR(edi, nullptr), { ehframe_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_edi_i386 }, nullptr, nullptr}, + { DEFINE_GPR(esi, nullptr), { ehframe_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_esi_i386 }, nullptr, nullptr}, + { DEFINE_GPR(ebp, "fp"), { ehframe_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, lldb_ebp_i386 }, nullptr, nullptr}, + { DEFINE_GPR(esp, "sp"), { ehframe_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, lldb_esp_i386 }, nullptr, nullptr}, + { DEFINE_GPR(eip, "pc"), { ehframe_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, lldb_eip_i386 }, nullptr, nullptr}, + { DEFINE_GPR_BIN(eflags, "flags"), { ehframe_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, lldb_eflags_i386}, nullptr, nullptr}, +}; + +// Array of lldb register numbers used to define the set of all General Purpose Registers +uint32_t g_gpr_reg_indices[] = +{ + eRegisterIndexEax, + eRegisterIndexEbx, + eRegisterIndexEcx, + eRegisterIndexEdx, + eRegisterIndexEdi, + eRegisterIndexEsi, + eRegisterIndexEbp, + eRegisterIndexEsp, + eRegisterIndexEip, + eRegisterIndexEflags +}; + +RegisterSet g_register_sets[] = { + {"General Purpose Registers", "gpr", llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices}, +}; +} + +//------------------------------------------------------------------ +// Constructors and Destructors +//------------------------------------------------------------------ +RegisterContextWindows_x86::RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx) + : RegisterContextWindows(thread, concrete_frame_idx) +{ +} + +RegisterContextWindows_x86::~RegisterContextWindows_x86() +{ +} + +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]; +} + Index: source/Plugins/Process/Windows/Live/CMakeLists.txt =================================================================== --- source/Plugins/Process/Windows/Live/CMakeLists.txt +++ source/Plugins/Process/Windows/Live/CMakeLists.txt @@ -5,19 +5,17 @@ set(PROC_WINDOWS_SOURCES DebuggerThread.cpp LocalDebugDelegate.cpp - ProcessWindows.cpp - ProcessWindowsLog.cpp - RegisterContextWindows.cpp - TargetThreadWindows.cpp + ProcessWindowsLive.cpp + TargetThreadWindowsLive.cpp ) if (CMAKE_SIZEOF_VOID_P EQUAL 4) set(PROC_WINDOWS_SOURCES ${PROC_WINDOWS_SOURCES} - x86/RegisterContextWindows_x86.cpp + x86/RegisterContextWindowsLive_x86.cpp ) elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) set(PROC_WINDOWS_SOURCES ${PROC_WINDOWS_SOURCES} - x64/RegisterContextWindows_x64.cpp + x64/RegisterContextWindowsLive_x64.cpp ) endif() Index: source/Plugins/Process/Windows/Live/DebuggerThread.cpp =================================================================== --- source/Plugins/Process/Windows/Live/DebuggerThread.cpp +++ source/Plugins/Process/Windows/Live/DebuggerThread.cpp @@ -24,7 +24,7 @@ #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/Process.h" -#include "Plugins/Process/Windows/Live/ProcessWindowsLog.h" +#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" Index: source/Plugins/Process/Windows/Live/ForwardDecl.h =================================================================== --- source/Plugins/Process/Windows/Live/ForwardDecl.h +++ source/Plugins/Process/Windows/Live/ForwardDecl.h @@ -1,41 +1,41 @@ -//===-- ForwardDecl.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_Plugins_Process_Windows_ForwardDecl_H_ -#define liblldb_Plugins_Process_Windows_ForwardDecl_H_ - -class ProcessWindows; - -#include - -// ExceptionResult is returned by the debug delegate to specify how it processed -// the exception. -enum class ExceptionResult -{ - BreakInDebugger, // Break in the debugger and give the user a chance to interact with - // the program before continuing. - MaskException, // Eat the exception and don't let the application know it occurred. - SendToApplication // Send the exception to the application to be handled as if there were - // no debugger attached. -}; - -namespace lldb_private -{ - -class IDebugDelegate; -class DebuggerThread; -class ExceptionRecord; - -typedef std::shared_ptr DebugDelegateSP; -typedef std::shared_ptr DebuggerThreadSP; -typedef std::shared_ptr ExceptionRecordSP; -typedef std::unique_ptr ExceptionRecordUP; -} - +//===-- ForwardDecl.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_Plugins_Process_Windows_ForwardDecl_H_ +#define liblldb_Plugins_Process_Windows_ForwardDecl_H_ + +#include + +// ExceptionResult is returned by the debug delegate to specify how it processed +// the exception. +enum class ExceptionResult +{ + BreakInDebugger, // Break in the debugger and give the user a chance to interact with + // the program before continuing. + MaskException, // Eat the exception and don't let the application know it occurred. + SendToApplication // Send the exception to the application to be handled as if there were + // no debugger attached. +}; + +namespace lldb_private +{ + +class ProcessWindows; + +class IDebugDelegate; +class DebuggerThread; +class ExceptionRecord; + +typedef std::shared_ptr DebugDelegateSP; +typedef std::shared_ptr DebuggerThreadSP; +typedef std::shared_ptr ExceptionRecordSP; +typedef std::unique_ptr ExceptionRecordUP; +} + #endif \ No newline at end of file Index: source/Plugins/Process/Windows/Live/LocalDebugDelegate.h =================================================================== --- source/Plugins/Process/Windows/Live/LocalDebugDelegate.h +++ source/Plugins/Process/Windows/Live/LocalDebugDelegate.h @@ -1,65 +1,69 @@ -//===-- LocalDebugDelegate.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_Plugins_Process_Windows_LocalDebugDelegate_H_ -#define liblldb_Plugins_Process_Windows_LocalDebugDelegate_H_ - -#include "IDebugDelegate.h" -#include "ProcessWindowsForward.h" - -#include "lldb/lldb-forward.h" - -class ProcessWindows; - -namespace lldb_private -{ -//---------------------------------------------------------------------- -// LocalDebugDelegate -// -// LocalDebugDelegate creates a connection between a ProcessWindows and the -// debug driver. This serves to decouple ProcessWindows from the debug driver. -// It would be possible to get a similar decoupling by just having -// ProcessWindows implement this interface directly. There are two reasons why -// we don't do this: -// -// 1) In the future when we add support for local debugging through LLGS, and we -// go through the Native*Protocol interface, it is likely we will need the -// additional flexibility provided by this sort of adapter pattern. -// 2) LLDB holds a shared_ptr to the ProcessWindows, and our driver thread -// needs access to it as well. To avoid a race condition, we want to make -// sure that we're also holding onto a shared_ptr. -// lldb_private::Process supports enable_shared_from_this, but that gives us -// a ProcessSP (which is exactly what we are trying to decouple from the -// driver), so this adapter serves as a way to transparently hold the -// ProcessSP while still keeping it decoupled from the driver. -//---------------------------------------------------------------------- -class LocalDebugDelegate : public IDebugDelegate -{ - public: - explicit LocalDebugDelegate(lldb::ProcessWP process); - - void OnExitProcess(uint32_t exit_code) override; - void OnDebuggerConnected(lldb::addr_t image_base) override; - ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) override; - void OnCreateThread(const HostThread &thread) override; - void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; - void OnDebugString(const std::string &message) override; - void OnDebuggerError(const Error &error, uint32_t type) override; - - private: - ProcessWindowsSP - GetProcessPointer(); - - lldb::ProcessWP m_process; -}; -} - -#endif +//===-- LocalDebugDelegate.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_Plugins_Process_Windows_LocalDebugDelegate_H_ +#define liblldb_Plugins_Process_Windows_LocalDebugDelegate_H_ + +#include + +#include "IDebugDelegate.h" +#include "ProcessWindowsForward.h" + +#include "lldb/lldb-forward.h" + +namespace lldb_private +{ + +class ProcessWindowsLive; +typedef std::shared_ptr ProcessWindowsLiveSP; + +//---------------------------------------------------------------------- +// LocalDebugDelegate +// +// LocalDebugDelegate creates a connection between a ProcessWindowsLive and the +// debug driver. This serves to decouple ProcessWindowsLive from the debug driver. +// It would be possible to get a similar decoupling by just having +// ProcessWindowsLive implement this interface directly. There are two reasons why +// we don't do this: +// +// 1) In the future when we add support for local debugging through LLGS, and we +// go through the Native*Protocol interface, it is likely we will need the +// additional flexibility provided by this sort of adapter pattern. +// 2) LLDB holds a shared_ptr to the ProcessWindows, and our driver thread +// needs access to it as well. To avoid a race condition, we want to make +// sure that we're also holding onto a shared_ptr. +// lldb_private::Process supports enable_shared_from_this, but that gives us +// a ProcessSP (which is exactly what we are trying to decouple from the +// driver), so this adapter serves as a way to transparently hold the +// ProcessSP while still keeping it decoupled from the driver. +//---------------------------------------------------------------------- +class LocalDebugDelegate : public IDebugDelegate +{ + public: + explicit LocalDebugDelegate(lldb::ProcessWP process); + + void OnExitProcess(uint32_t exit_code) override; + void OnDebuggerConnected(lldb::addr_t image_base) override; + ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) override; + void OnCreateThread(const HostThread &thread) override; + void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; + void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; + void OnUnloadDll(lldb::addr_t module_addr) override; + void OnDebugString(const std::string &message) override; + void OnDebuggerError(const Error &error, uint32_t type) override; + + private: + ProcessWindowsLiveSP + GetProcessPointer(); + + lldb::ProcessWP m_process; +}; +} + +#endif Index: source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp =================================================================== --- source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp +++ source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp @@ -1,91 +1,91 @@ -//===-- LocalDebugDelegate.cpp ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "LocalDebugDelegate.h" -#include "ProcessWindows.h" - -using namespace lldb; -using namespace lldb_private; - -LocalDebugDelegate::LocalDebugDelegate(ProcessWP process) - : m_process(process) -{ -} - -void -LocalDebugDelegate::OnExitProcess(uint32_t exit_code) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnExitProcess(exit_code); -} - -void -LocalDebugDelegate::OnDebuggerConnected(lldb::addr_t image_base) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnDebuggerConnected(image_base); -} - -ExceptionResult -LocalDebugDelegate::OnDebugException(bool first_chance, const ExceptionRecord &record) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - return process->OnDebugException(first_chance, record); - else - return ExceptionResult::MaskException; -} - -void -LocalDebugDelegate::OnCreateThread(const HostThread &thread) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnCreateThread(thread); -} - -void -LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnExitThread(thread_id, exit_code); -} - -void -LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnLoadDll(module_spec, module_addr); -} - -void -LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnUnloadDll(module_addr); -} - -void -LocalDebugDelegate::OnDebugString(const std::string &string) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnDebugString(string); -} - -void -LocalDebugDelegate::OnDebuggerError(const Error &error, uint32_t type) -{ - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnDebuggerError(error, type); -} - -ProcessWindowsSP -LocalDebugDelegate::GetProcessPointer() -{ - ProcessSP process = m_process.lock(); - return std::static_pointer_cast(process); -} +//===-- LocalDebugDelegate.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LocalDebugDelegate.h" +#include "ProcessWindowsLive.h" + +using namespace lldb; +using namespace lldb_private; + +LocalDebugDelegate::LocalDebugDelegate(ProcessWP process) + : m_process(process) +{ +} + +void +LocalDebugDelegate::OnExitProcess(uint32_t exit_code) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnExitProcess(exit_code); +} + +void +LocalDebugDelegate::OnDebuggerConnected(lldb::addr_t image_base) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnDebuggerConnected(image_base); +} + +ExceptionResult +LocalDebugDelegate::OnDebugException(bool first_chance, const ExceptionRecord &record) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + return process->OnDebugException(first_chance, record); + else + return ExceptionResult::MaskException; +} + +void +LocalDebugDelegate::OnCreateThread(const HostThread &thread) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnCreateThread(thread); +} + +void +LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnExitThread(thread_id, exit_code); +} + +void +LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnLoadDll(module_spec, module_addr); +} + +void +LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnUnloadDll(module_addr); +} + +void +LocalDebugDelegate::OnDebugString(const std::string &string) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnDebugString(string); +} + +void +LocalDebugDelegate::OnDebuggerError(const Error &error, uint32_t type) +{ + if (ProcessWindowsLiveSP process = GetProcessPointer()) + process->OnDebuggerError(error, type); +} + +ProcessWindowsLiveSP +LocalDebugDelegate::GetProcessPointer() +{ + ProcessSP process = m_process.lock(); + return std::static_pointer_cast(process); +} Index: source/Plugins/Process/Windows/Live/ProcessWindows.h =================================================================== --- source/Plugins/Process/Windows/Live/ProcessWindows.h +++ /dev/null @@ -1,127 +0,0 @@ -//===-- ProcessWindows.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_Plugins_Process_Windows_ProcessWindows_H_ -#define liblldb_Plugins_Process_Windows_ProcessWindows_H_ - -// C Includes - -// C++ Includes -#include -#include - -// Other libraries and framework includes -#include "ForwardDecl.h" -#include "IDebugDelegate.h" -#include "lldb/lldb-forward.h" -#include "lldb/Core/Error.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Target/Process.h" - -#include "llvm/Support/Mutex.h" - -class ProcessMonitor; - -namespace lldb_private -{ -class HostProcess; -class ProcessWindowsData; -} - -class ProcessWindows : public lldb_private::Process, public lldb_private::IDebugDelegate -{ -public: - //------------------------------------------------------------------ - // Static functions. - //------------------------------------------------------------------ - static lldb::ProcessSP - CreateInstance(lldb::TargetSP target_sp, - lldb_private::Listener &listener, - const lldb_private::FileSpec *); - - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::ConstString - GetPluginNameStatic(); - - static const char * - GetPluginDescriptionStatic(); - - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - ProcessWindows(lldb::TargetSP target_sp, - lldb_private::Listener &listener); - - ~ProcessWindows(); - - // lldb_private::Process overrides - lldb_private::ConstString GetPluginName() override; - uint32_t GetPluginVersion() override; - - size_t GetSTDOUT(char *buf, size_t buf_size, lldb_private::Error &error) override; - size_t GetSTDERR(char *buf, size_t buf_size, lldb_private::Error &error) override; - size_t PutSTDIN(const char *buf, size_t buf_size, lldb_private::Error &error) override; - - lldb_private::Error EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - lldb_private::Error DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - lldb_private::Error DoDetach(bool keep_stopped) override; - lldb_private::Error DoLaunch(lldb_private::Module *exe_module, lldb_private::ProcessLaunchInfo &launch_info) override; - lldb_private::Error DoAttachToProcessWithID(lldb::pid_t pid, - const lldb_private::ProcessAttachInfo &attach_info) override; - lldb_private::Error DoResume() override; - lldb_private::Error DoDestroy() override; - lldb_private::Error DoHalt(bool &caused_stop) override; - - void DidLaunch() override; - void DidAttach(lldb_private::ArchSpec &arch_spec) override; - - void RefreshStateAfterStop() override; - lldb::addr_t GetImageInfoAddress() override; - - bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override; - bool - DestroyRequiresHalt() override - { - return false; - } - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override; - bool IsAlive() override; - - size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, lldb_private::Error &error) override; - size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, lldb_private::Error &error) override; - lldb_private::Error GetMemoryRegionInfo(lldb::addr_t vm_addr, lldb_private::MemoryRegionInfo &info) override; - - // IDebugDelegate overrides. - void OnExitProcess(uint32_t exit_code) override; - void OnDebuggerConnected(lldb::addr_t image_base) override; - ExceptionResult OnDebugException(bool first_chance, const lldb_private::ExceptionRecord &record) override; - void OnCreateThread(const lldb_private::HostThread &thread) override; - void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; - void OnDebugString(const std::string &string) override; - void OnDebuggerError(const lldb_private::Error &error, uint32_t type) override; - - private: - lldb_private::Error WaitForDebuggerConnection(lldb_private::DebuggerThreadSP debugger, - lldb_private::HostProcess &process); - - llvm::sys::Mutex m_mutex; - - // Data for the active debugging session. - std::unique_ptr m_session_data; -}; - -#endif // liblldb_Plugins_Process_Windows_ProcessWindows_H_ Index: source/Plugins/Process/Windows/Live/ProcessWindows.cpp =================================================================== --- source/Plugins/Process/Windows/Live/ProcessWindows.cpp +++ /dev/null @@ -1,1021 +0,0 @@ -//===-- ProcessWindows.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// Windows includes -#include "lldb/Host/windows/windows.h" -#include - -// C++ Includes -#include -#include -#include -#include - -// Other libraries and framework includes -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/Section.h" -#include "lldb/Core/State.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostProcess.h" -#include "lldb/Host/HostNativeProcessBase.h" -#include "lldb/Host/HostNativeThreadBase.h" -#include "lldb/Host/MonitoringProcessLauncher.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/ProcessLauncherWindows.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/FileAction.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" - -#include "Plugins/Process/Windows/Live/ProcessWindowsForward.h" -#include "Plugins/Process/Windows/live/ProcessWindowsLog.h" - -#include "DebuggerThread.h" -#include "ExceptionRecord.h" -#include "LocalDebugDelegate.h" -#include "ProcessWindows.h" -#include "TargetThreadWindows.h" - -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lldb; -using namespace lldb_private; - -#define BOOL_STR(b) ((b) ? "true" : "false") - -namespace -{ - -std::string -GetProcessExecutableName(HANDLE process_handle) -{ - std::vector file_name; - DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit - DWORD copied = 0; - do - { - file_name_size *= 2; - file_name.resize(file_name_size); - copied = ::GetModuleFileNameEx(process_handle, NULL, file_name.data(), file_name_size); - } while (copied >= file_name_size); - file_name.resize(copied); - return std::string(file_name.begin(), file_name.end()); -} - -std::string -GetProcessExecutableName(DWORD pid) -{ - std::string file_name; - HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); - if (process_handle != NULL) - { - file_name = GetProcessExecutableName(process_handle); - ::CloseHandle(process_handle); - } - return file_name; -} - -} // anonymous namespace - -namespace lldb_private -{ - -// We store a pointer to this class in the ProcessWindows, so that we don't expose Windows -// OS specific types and implementation details from a public header file. -class ProcessWindowsData -{ - public: - ProcessWindowsData(bool stop_at_entry) - : m_stop_at_entry(stop_at_entry) - , m_initial_stop_event(nullptr) - , m_initial_stop_received(false) - { - m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); - } - - ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } - - lldb_private::Error m_launch_error; - lldb_private::DebuggerThreadSP m_debugger; - StopInfoSP m_pending_stop_info; - HANDLE m_initial_stop_event; - bool m_stop_at_entry; - bool m_initial_stop_received; - std::map m_new_threads; - std::set m_exited_threads; -}; -} -//------------------------------------------------------------------------------ -// Static functions. - -ProcessSP -ProcessWindows::CreateInstance(lldb::TargetSP target_sp, Listener &listener, const FileSpec *) -{ - return ProcessSP(new ProcessWindows(target_sp, listener)); -} - -void -ProcessWindows::Initialize() -{ - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, []() - { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); - }); -} - -//------------------------------------------------------------------------------ -// Constructors and destructors. - -ProcessWindows::ProcessWindows(lldb::TargetSP target_sp, Listener &listener) - : lldb_private::Process(target_sp, listener) -{ -} - -ProcessWindows::~ProcessWindows() -{ -} - -void -ProcessWindows::Terminate() -{ -} - -lldb_private::ConstString -ProcessWindows::GetPluginNameStatic() -{ - static ConstString g_name("windows"); - return g_name; -} - -const char * -ProcessWindows::GetPluginDescriptionStatic() -{ - return "Process plugin for Windows"; -} - -size_t -ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Error &error) -{ - error.SetErrorString("GetSTDOUT unsupported on Windows"); - return 0; -} - -size_t -ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Error &error) -{ - error.SetErrorString("GetSTDERR unsupported on Windows"); - return 0; -} - -size_t -ProcessWindows::PutSTDIN(const char *buf, size_t buf_size, Error &error) -{ - error.SetErrorString("PutSTDIN unsupported on Windows"); - return 0; -} - -Error -ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) -{ - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite called with bp_site 0x%p " - "(id=%d, addr=0x%x)", - bp_site->GetID(), bp_site->GetLoadAddress()); - - Error error = EnableSoftwareBreakpoint(bp_site); - if (!error.Success()) - { - WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite failed. %s", error.AsCString()); - } - return error; -} - -Error -ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) -{ - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite called with bp_site 0x%p " - "(id=%d, addr=0x%x)", - bp_site->GetID(), bp_site->GetLoadAddress()); - - Error error = DisableSoftwareBreakpoint(bp_site); - - if (!error.Success()) - { - WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite failed. %s", error.AsCString()); - } - return error; -} - -bool -ProcessWindows::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) -{ - // Add all the threads that were previously running and for which we did not detect a thread - // exited event. - int new_size = 0; - int continued_threads = 0; - int exited_threads = 0; - int new_threads = 0; - - for (ThreadSP old_thread : old_thread_list.Threads()) - { - lldb::tid_t old_thread_id = old_thread->GetID(); - auto exited_thread_iter = m_session_data->m_exited_threads.find(old_thread_id); - if (exited_thread_iter == m_session_data->m_exited_threads.end()) - { - new_thread_list.AddThread(old_thread); - ++new_size; - ++continued_threads; - WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u was running and is still running.", - old_thread_id); - } - else - { - WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u was running and has exited.", - old_thread_id); - ++exited_threads; - } - } - - // Also add all the threads that are new since the last time we broke into the debugger. - for (const auto &thread_info : m_session_data->m_new_threads) - { - ThreadSP thread(new TargetThreadWindows(*this, thread_info.second)); - thread->SetID(thread_info.first); - new_thread_list.AddThread(thread); - ++new_size; - ++new_threads; - WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u is new since last update.", thread_info.first); - } - - WINLOG_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - %d new threads, %d old threads, %d exited threads.", - new_threads, continued_threads, exited_threads); - - m_session_data->m_new_threads.clear(); - m_session_data->m_exited_threads.clear(); - - return new_size > 0; -} - -Error -ProcessWindows::DoLaunch(Module *exe_module, - ProcessLaunchInfo &launch_info) -{ - // Even though m_session_data is accessed here, it is before a debugger thread has been - // kicked off. So there's no race conditions, and it shouldn't be necessary to acquire - // the mutex. - - Error result; - if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) - { - StreamString stream; - stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can only be used for debug launches.", - launch_info.GetExecutableFile().GetPath().c_str()); - std::string message = stream.GetString(); - result.SetErrorString(message.c_str()); - - WINERR_IFALL(WINDOWS_LOG_PROCESS, message.c_str()); - return result; - } - - bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); - m_session_data.reset(new ProcessWindowsData(stop_at_entry)); - - SetPrivateState(eStateLaunching); - DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - m_session_data->m_debugger.reset(new DebuggerThread(delegate)); - DebuggerThreadSP debugger = m_session_data->m_debugger; - - // Kick off the DebugLaunch asynchronously and wait for it to complete. - result = debugger->DebugLaunch(launch_info); - if (result.Fail()) - { - WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", - launch_info.GetExecutableFile().GetPath().c_str(), result.AsCString()); - return result; - } - - HostProcess process; - Error error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) - { - WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", - launch_info.GetExecutableFile().GetPath().c_str(), error.AsCString()); - return error; - } - - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'", - launch_info.GetExecutableFile().GetPath().c_str()); - - // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state - // should already be set to eStateStopped as a result of hitting the initial breakpoint. If - // it was not set, the breakpoint should have already been resumed from and the private state - // should already be eStateRunning. - launch_info.SetProcessID(process.GetProcessId()); - SetID(process.GetProcessId()); - - return result; -} - -Error -ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid, const ProcessAttachInfo &attach_info) -{ - m_session_data.reset(new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); - - DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - DebuggerThreadSP debugger(new DebuggerThread(delegate)); - - m_session_data->m_debugger = debugger; - - DWORD process_id = static_cast(pid); - Error error = debugger->DebugAttach(process_id, attach_info); - if (error.Fail()) - { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, - "DoAttachToProcessWithID encountered an error occurred initiating the asynchronous attach. %s", - error.AsCString()); - return error; - } - - HostProcess process; - error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) - { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, - "DoAttachToProcessWithID encountered an error waiting for the debugger to connect. %s", - error.AsCString()); - return error; - } - - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID successfully attached to process with pid=%u", - process_id); - - // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state - // should already be set to eStateStopped as a result of hitting the initial breakpoint. If - // it was not set, the breakpoint should have already been resumed from and the private state - // should already be eStateRunning. - SetID(process.GetProcessId()); - return error; -} - -Error -ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger, HostProcess &process) -{ - Error result; - WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection Waiting for loader breakpoint."); - - // Block this function until we receive the initial stop from the process. - if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0) - { - WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection hit loader breakpoint, returning."); - - process = debugger->GetProcess(); - return m_session_data->m_launch_error; - } - else - return Error(::GetLastError(), eErrorTypeWin32); -} - -Error -ProcessWindows::DoResume() -{ - llvm::sys::ScopedLock lock(m_mutex); - Error error; - - StateType private_state = GetPrivateState(); - if (private_state == eStateStopped || private_state == eStateCrashed) - { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoResume called for process %I64u while state is %u. Resuming...", - m_session_data->m_debugger->GetProcess().GetProcessId(), GetPrivateState()); - - ExceptionRecordSP active_exception = - m_session_data->m_debugger->GetActiveException().lock(); - if (active_exception) - { - // Resume the process and continue processing debug events. Mask - // the exception so that from the process's view, there is no - // indication that anything happened. - m_session_data->m_debugger->ContinueAsyncException( - ExceptionResult::MaskException); - } - - WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_THREAD, "DoResume resuming %u threads.", - m_thread_list.GetSize()); - - for (int i = 0; i < m_thread_list.GetSize(); ++i) - { - auto thread = std::static_pointer_cast( - m_thread_list.GetThreadAtIndex(i)); - thread->DoResume(); - } - - SetPrivateState(eStateRunning); - } - else - { - WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoResume called for process %I64u but state is %u. Returning...", - m_session_data->m_debugger->GetProcess().GetProcessId(), GetPrivateState()); - } - return error; -} - - -//------------------------------------------------------------------------------ -// ProcessInterface protocol. - -lldb_private::ConstString -ProcessWindows::GetPluginName() -{ - return GetPluginNameStatic(); -} - -uint32_t -ProcessWindows::GetPluginVersion() -{ - return 1; -} - -Error -ProcessWindows::DoDetach(bool keep_stopped) -{ - DebuggerThreadSP debugger_thread; - StateType private_state; - { - // Acquire the lock only long enough to get the DebuggerThread. - // StopDebugging() will trigger a call back into ProcessWindows which - // will also acquire the lock. Thus we have to release the lock before - // calling StopDebugging(). - llvm::sys::ScopedLock lock(m_mutex); - - private_state = GetPrivateState(); - - if (!m_session_data) - { - WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDetach called while state = %u, but there is no active session.", - private_state); - return Error(); - } - - debugger_thread = m_session_data->m_debugger; - } - - Error error; - if (private_state != eStateExited && private_state != eStateDetached) - { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDetach called for process %I64u while state = %u. Detaching...", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); - error = debugger_thread->StopDebugging(false); - if (error.Success()) - { - SetPrivateState(eStateDetached); - } - - // By the time StopDebugging returns, there is no more debugger thread, so - // we can be assured that no other thread will race for the session data. - m_session_data.reset(); - } - else - { - WINERR_IFALL(WINDOWS_LOG_PROCESS, - "DoDetach called for process %I64u while state = %u, but cannot destroy in this state.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); - } - - return error; -} - -Error -ProcessWindows::DoDestroy() -{ - DebuggerThreadSP debugger_thread; - StateType private_state; - { - // Acquire this lock inside an inner scope, only long enough to get the DebuggerThread. - // StopDebugging() will trigger a call back into ProcessWindows which will acquire the lock - // again, so we need to not deadlock. - llvm::sys::ScopedLock lock(m_mutex); - - private_state = GetPrivateState(); - - if (!m_session_data) - { - WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called while state = %u, but there is no active session.", - private_state); - return Error(); - } - - debugger_thread = m_session_data->m_debugger; - } - - Error error; - if (private_state != eStateExited && private_state != eStateDetached) - { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called for process %I64u while state = %u. Shutting down...", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); - error = debugger_thread->StopDebugging(true); - - // By the time StopDebugging returns, there is no more debugger thread, so - // we can be assured that no other thread will race for the session data. - m_session_data.reset(); - } - else - { - WINERR_IFALL(WINDOWS_LOG_PROCESS, - "DoDestroy called for process %I64u while state = %u, but cannot destroy in this state.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); - } - - return error; -} - -void -ProcessWindows::RefreshStateAfterStop() -{ - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) - { - WINWARN_IFALL(WINDOWS_LOG_PROCESS, "RefreshStateAfterStop called with no active session. Returning..."); - return; - } - - m_thread_list.RefreshStateAfterStop(); - - std::weak_ptr exception_record = m_session_data->m_debugger->GetActiveException(); - ExceptionRecordSP active_exception = exception_record.lock(); - if (!active_exception) - { - WINERR_IFALL(WINDOWS_LOG_PROCESS, "RefreshStateAfterStop called for process %I64u but there is no " - "active exception. Why is the process stopped?", - m_session_data->m_debugger->GetProcess().GetProcessId()); - return; - } - - StopInfoSP stop_info; - m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID()); - ThreadSP stop_thread = m_thread_list.GetSelectedThread(); - if (!stop_thread) - return; - - RegisterContextSP register_context = stop_thread->GetRegisterContext(); - - // The current EIP is AFTER the BP opcode, which is one byte. - uint64_t pc = register_context->GetPC() - 1; - if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT) - { - BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); - - if (site) - { - WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "RefreshStateAfterStop detected breakpoint in process %I64u at " - "address 0x%I64x with breakpoint site %d", - m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID()); - - if (site->ValidForThisThread(stop_thread.get())) - { - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.", - site->GetID(), stop_thread->GetID()); - - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( - *stop_thread, site->GetID()); - register_context->SetPC(pc); - } - else - { - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "Breakpoint site %d is not valid for this thread, creating empty stop info.", - site->GetID()); - } - } - stop_thread->SetStopInfo(stop_info); - } - else if (active_exception->GetExceptionCode() == EXCEPTION_SINGLE_STEP) - { - stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); - stop_thread->SetStopInfo(stop_info); - WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u", - stop_thread->GetID()); - } - else - { - std::string desc; - llvm::raw_string_ostream desc_stream(desc); - desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8) - << " encountered at address " << llvm::format_hex(pc, 8); - stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str()); - stop_thread->SetStopInfo(stop_info); - WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str()); - } -} - -bool -ProcessWindows::IsAlive() -{ - StateType state = GetPrivateState(); - switch (state) - { - case eStateCrashed: - case eStateDetached: - case eStateUnloaded: - case eStateExited: - case eStateInvalid: - return false; - default: - return true; - } -} - -Error -ProcessWindows::DoHalt(bool &caused_stop) -{ - Error error; - StateType state = GetPrivateState(); - if (state == eStateStopped) - caused_stop = false; - else - { - llvm::sys::ScopedLock lock(m_mutex); - caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess().GetNativeProcess().GetSystemHandle()); - if (!caused_stop) - { - error.SetError(::GetLastError(), eErrorTypeWin32); - WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoHalt called DebugBreakProcess, but it failed with error %u", - error.GetError()); - } - } - return error; -} - -void ProcessWindows::DidLaunch() -{ - ArchSpec arch_spec; - DidAttach(arch_spec); -} - -void -ProcessWindows::DidAttach(ArchSpec &arch_spec) -{ - llvm::sys::ScopedLock lock(m_mutex); - - // The initial stop won't broadcast the state change event, so account for that here. - if (m_session_data && GetPrivateState() == eStateStopped && m_session_data->m_stop_at_entry) - RefreshStateAfterStop(); -} - -size_t -ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, - void *buf, - size_t size, - Error &error) -{ - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) - return 0; - - WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory attempting to read %u bytes from address 0x%I64x", size, vm_addr); - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast(vm_addr); - SIZE_T bytes_read = 0; - if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, buf, size, &bytes_read)) - { - error.SetError(GetLastError(), eErrorTypeWin32); - WINERR_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory failed with error code %u", error.GetError()); - } - return bytes_read; -} - -size_t -ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) -{ - llvm::sys::ScopedLock lock(m_mutex); - WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, vm_addr); - - if (!m_session_data) - { - WINERR_IFANY(WINDOWS_LOG_MEMORY, "DoWriteMemory cannot write, there is no active debugger connection."); - return 0; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast(vm_addr); - SIZE_T bytes_written = 0; - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (WriteProcessMemory(handle, addr, buf, size, &bytes_written)) - FlushInstructionCache(handle, addr, bytes_written); - else - { - error.SetError(GetLastError(), eErrorTypeWin32); - WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory failed with error code %u", error.GetError()); - } - return bytes_written; -} - -Error -ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info) -{ - Error error; - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) - { - error.SetErrorString("GetMemoryRegionInfo called with no debugging session."); - WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString()); - return error; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (handle == nullptr || handle == LLDB_INVALID_PROCESS) - { - error.SetErrorString("GetMemoryRegionInfo called with an invalid target process."); - WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString()); - return error; - } - - WINLOG_IFALL(WINDOWS_LOG_MEMORY, "GetMemoryRegionInfo getting info for address 0x%I64x", vm_addr); - - void *addr = reinterpret_cast(vm_addr); - MEMORY_BASIC_INFORMATION mem_info = {0}; - SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); - if (result == 0) - { - error.SetError(::GetLastError(), eErrorTypeWin32); - WINERR_IFALL(WINDOWS_LOG_MEMORY, - "VirtualQueryEx returned error %u while getting memory region info for address 0x%I64x", - error.GetError(), vm_addr); - return error; - } - bool readable = !(mem_info.Protect & PAGE_NOACCESS); - bool executable = mem_info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); - bool writable = mem_info.Protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READWRITE | PAGE_WRITECOPY); - info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); - info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); - info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); - error.SetError(::GetLastError(), eErrorTypeWin32); - WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address 0x%I64u: readable=%s, executable=%s, writable=%s", - BOOL_STR(readable), BOOL_STR(executable), BOOL_STR(writable)); - return error; -} - -lldb::addr_t -ProcessWindows::GetImageInfoAddress() -{ - Target &target = GetTarget(); - ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(&target); - if (addr.IsValid()) - return addr.GetLoadAddress(&target); - else - return LLDB_INVALID_ADDRESS; -} - -bool -ProcessWindows::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) -{ - if (plugin_specified_by_name) - return true; - - // For now we are just making sure the file exists for a given module - ModuleSP exe_module_sp(target_sp->GetExecutableModule()); - if (exe_module_sp.get()) - return exe_module_sp->GetFileSpec().Exists(); - // However, if there is no executable module, we return true since we might be preparing to attach. - return true; -} - -void -ProcessWindows::OnExitProcess(uint32_t exit_code) -{ - // No need to acquire the lock since m_session_data isn't accessed. - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Process %u exited with code %u", GetID(), exit_code); - - TargetSP target = m_target_sp.lock(); - if (target) - { - ModuleSP executable_module = target->GetExecutableModule(); - ModuleList unloaded_modules; - unloaded_modules.Append(executable_module); - target->ModulesDidUnload(unloaded_modules, true); - } - - SetProcessExitStatus(nullptr, GetID(), true, 0, exit_code); - SetPrivateState(eStateExited); -} - -void -ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) -{ - DebuggerThreadSP debugger = m_session_data->m_debugger; - - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Debugger connected to process %I64u. Image base = 0x%I64x", - debugger->GetProcess().GetProcessId(), image_base); - - ModuleSP module = GetTarget().GetExecutableModule(); - if (!module) - { - // During attach, we won't have the executable module, so find it now. - const DWORD pid = debugger->GetProcess().GetProcessId(); - const std::string file_name = GetProcessExecutableName(pid); - if (file_name.empty()) - { - return; - } - - FileSpec executable_file(file_name, true); - ModuleSpec module_spec(executable_file); - Error error; - module = GetTarget().GetSharedModule(module_spec, &error); - if (!module) - { - return; - } - - GetTarget().SetExecutableModule(module, false); - } - - bool load_addr_changed; - module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed); - - ModuleList loaded_modules; - loaded_modules.Append(module); - GetTarget().ModulesDidLoad(loaded_modules); - - // Add the main executable module to the list of pending module loads. We can't call - // GetTarget().ModulesDidLoad() here because we still haven't returned from DoLaunch() / DoAttach() yet - // so the target may not have set the process instance to `this` yet. - llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wmain_thread = debugger->GetMainThread().GetNativeThread(); - m_session_data->m_new_threads[wmain_thread.GetThreadId()] = debugger->GetMainThread(); -} - -ExceptionResult -ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &record) -{ - llvm::sys::ScopedLock lock(m_mutex); - - // FIXME: Without this check, occasionally when running the test suite there is - // an issue where m_session_data can be null. It's not clear how this could happen - // but it only surfaces while running the test suite. In order to properly diagnose - // this, we probably need to first figure allow the test suite to print out full - // lldb logs, and then add logging to the process plugin. - if (!m_session_data) - { - WINERR_IFANY(WINDOWS_LOG_EXCEPTION, - "Debugger thread reported exception 0x%x at address 0x%I64x, but there is no session.", - record.GetExceptionCode(), record.GetExceptionAddress()); - return ExceptionResult::SendToApplication; - } - - if (!first_chance) - { - // Any second chance exception is an application crash by definition. - SetPrivateState(eStateCrashed); - } - - ExceptionResult result = ExceptionResult::SendToApplication; - switch (record.GetExceptionCode()) - { - case EXCEPTION_BREAKPOINT: - // Handle breakpoints at the first chance. - result = ExceptionResult::BreakInDebugger; - - if (!m_session_data->m_initial_stop_received) - { - WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, - "Hit loader breakpoint at address 0x%I64x, setting initial stop event.", - record.GetExceptionAddress()); - m_session_data->m_initial_stop_received = true; - ::SetEvent(m_session_data->m_initial_stop_event); - } - else - { - WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, - "Hit non-loader breakpoint at address 0x%I64x.", - record.GetExceptionAddress()); - } - SetPrivateState(eStateStopped); - break; - case EXCEPTION_SINGLE_STEP: - result = ExceptionResult::BreakInDebugger; - SetPrivateState(eStateStopped); - break; - default: - WINLOG_IFANY(WINDOWS_LOG_EXCEPTION, - "Debugger thread reported exception 0x%x at address 0x%I64x (first_chance=%s)", - record.GetExceptionCode(), record.GetExceptionAddress(), BOOL_STR(first_chance)); - // For non-breakpoints, give the application a chance to handle the exception first. - if (first_chance) - result = ExceptionResult::SendToApplication; - else - result = ExceptionResult::BreakInDebugger; - } - - return result; -} - -void -ProcessWindows::OnCreateThread(const HostThread &new_thread) -{ - llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wnew_thread = new_thread.GetNativeThread(); - m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread; -} - -void -ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) -{ - llvm::sys::ScopedLock lock(m_mutex); - - // On a forced termination, we may get exit thread events after the session - // data has been cleaned up. - if (!m_session_data) - return; - - // A thread may have started and exited before the debugger stopped allowing a refresh. - // Just remove it from the new threads list in that case. - auto iter = m_session_data->m_new_threads.find(thread_id); - if (iter != m_session_data->m_new_threads.end()) - m_session_data->m_new_threads.erase(iter); - else - m_session_data->m_exited_threads.insert(thread_id); -} - -void -ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) -{ - // Confusingly, there is no Target::AddSharedModule. Instead, calling GetSharedModule() with - // a new module will add it to the module list and return a corresponding ModuleSP. - Error error; - ModuleSP module = GetTarget().GetSharedModule(module_spec, &error); - bool load_addr_changed = false; - module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed); - - ModuleList loaded_modules; - loaded_modules.Append(module); - GetTarget().ModulesDidLoad(loaded_modules); -} - -void -ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) -{ - Address resolved_addr; - if (GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) - { - ModuleSP module = resolved_addr.GetModule(); - if (module) - { - ModuleList unloaded_modules; - unloaded_modules.Append(module); - GetTarget().ModulesDidUnload(unloaded_modules, false); - } - } -} - -void -ProcessWindows::OnDebugString(const std::string &string) -{ -} - -void -ProcessWindows::OnDebuggerError(const Error &error, uint32_t type) -{ - llvm::sys::ScopedLock lock(m_mutex); - - if (m_session_data->m_initial_stop_received) - { - // This happened while debugging. Do we shutdown the debugging session, try to continue, - // or do something else? - WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred during debugging. Unexpected behavior may result. %s", - error.GetError(), error.AsCString()); - } - else - { - // If we haven't actually launched the process yet, this was an error launching the - // process. Set the internal error and signal the initial stop event so that the DoLaunch - // method wakes up and returns a failure. - m_session_data->m_launch_error = error; - ::SetEvent(m_session_data->m_initial_stop_event); - WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred launching the process before the initial stop. %s", - error.GetError(), error.AsCString()); - return; - } -} \ No newline at end of file Index: source/Plugins/Process/Windows/Live/ProcessWindowsForward.h =================================================================== --- source/Plugins/Process/Windows/Live/ProcessWindowsForward.h +++ /dev/null @@ -1,19 +0,0 @@ -//===-- ProcessWindows.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_Plugins_Process_Windows_ProcessWindowsForward_H_ -#define liblldb_Plugins_Process_Windows_ProcessWindowsForward_H_ - -#include - -class ProcessWindows; - -typedef std::shared_ptr ProcessWindowsSP; - -#endif \ No newline at end of file Index: source/Plugins/Process/Windows/Live/ProcessWindowsLive.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Live/ProcessWindowsLive.h @@ -0,0 +1,125 @@ +//===-- ProcessWindowsLive.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_Plugins_Process_Windows_Live_ProcessWindowsLive_H_ +#define liblldb_Plugins_Process_Windows_Live_ProcessWindowsLive_H_ + +// C Includes + +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "ForwardDecl.h" +#include "IDebugDelegate.h" +#include "lldb/lldb-forward.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/Process.h" + +#include "llvm/Support/Mutex.h" + +#include "plugins/Process/Windows/Common/ProcessWindows.h" + +class ProcessMonitor; + +namespace lldb_private +{ +class HostProcess; +class ProcessWindowsData; + +class ProcessWindowsLive : public lldb_private::ProcessWindows, public lldb_private::IDebugDelegate +{ +public: + //------------------------------------------------------------------ + // Static functions. + //------------------------------------------------------------------ + static lldb::ProcessSP + CreateInstance(lldb::TargetSP target_sp, + lldb_private::Listener &listener, + const lldb_private::FileSpec *); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + //------------------------------------------------------------------ + // Constructors and destructors + //------------------------------------------------------------------ + ProcessWindowsLive(lldb::TargetSP target_sp, + lldb_private::Listener &listener); + + ~ProcessWindowsLive(); + + // lldb_private::Process overrides + lldb_private::ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; + + lldb_private::Error EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; + lldb_private::Error DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; + + lldb_private::Error DoDetach(bool keep_stopped) override; + lldb_private::Error DoLaunch(lldb_private::Module *exe_module, lldb_private::ProcessLaunchInfo &launch_info) override; + lldb_private::Error DoAttachToProcessWithID(lldb::pid_t pid, + const lldb_private::ProcessAttachInfo &attach_info) override; + lldb_private::Error DoResume() override; + lldb_private::Error DoDestroy() override; + lldb_private::Error DoHalt(bool &caused_stop) override; + + void DidLaunch() override; + void DidAttach(lldb_private::ArchSpec &arch_spec) override; + + void RefreshStateAfterStop() override; + + bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override; + bool + DestroyRequiresHalt() override + { + return false; + } + bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override; + bool IsAlive() override; + + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, lldb_private::Error &error) override; + size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, lldb_private::Error &error) override; + lldb_private::Error GetMemoryRegionInfo(lldb::addr_t vm_addr, lldb_private::MemoryRegionInfo &info) override; + + // IDebugDelegate overrides. + void OnExitProcess(uint32_t exit_code) override; + void OnDebuggerConnected(lldb::addr_t image_base) override; + ExceptionResult OnDebugException(bool first_chance, const lldb_private::ExceptionRecord &record) override; + void OnCreateThread(const lldb_private::HostThread &thread) override; + void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; + void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; + void OnUnloadDll(lldb::addr_t module_addr) override; + void OnDebugString(const std::string &string) override; + void OnDebuggerError(const lldb_private::Error &error, uint32_t type) override; + + private: + lldb_private::Error WaitForDebuggerConnection(lldb_private::DebuggerThreadSP debugger, + lldb_private::HostProcess &process); + + llvm::sys::Mutex m_mutex; + + // Data for the active debugging session. + std::unique_ptr m_session_data; +}; + +} + +#endif // liblldb_Plugins_Process_Windows_Live_ProcessWindowsLive_H_ Index: source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp @@ -0,0 +1,988 @@ +//===-- ProcessWindowsLive.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Windows includes +#include "lldb/Host/windows/windows.h" +#include + +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/State.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/HostNativeProcessBase.h" +#include "lldb/Host/HostNativeThreadBase.h" +#include "lldb/Host/MonitoringProcessLauncher.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/windows/HostThreadWindows.h" +#include "lldb/Host/windows/ProcessLauncherWindows.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/FileAction.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" + +#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" + +#include "DebuggerThread.h" +#include "ExceptionRecord.h" +#include "LocalDebugDelegate.h" +#include "ProcessWindowsLive.h" +#include "TargetThreadWindowsLive.h" + +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace lldb; +using namespace lldb_private; + +#define BOOL_STR(b) ((b) ? "true" : "false") + +namespace +{ + +std::string +GetProcessExecutableName(HANDLE process_handle) +{ + std::vector file_name; + DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit + DWORD copied = 0; + do + { + file_name_size *= 2; + file_name.resize(file_name_size); + copied = ::GetModuleFileNameEx(process_handle, NULL, file_name.data(), file_name_size); + } while (copied >= file_name_size); + file_name.resize(copied); + return std::string(file_name.begin(), file_name.end()); +} + +std::string +GetProcessExecutableName(DWORD pid) +{ + std::string file_name; + HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + if (process_handle != NULL) + { + file_name = GetProcessExecutableName(process_handle); + ::CloseHandle(process_handle); + } + return file_name; +} + +} // anonymous namespace + +namespace lldb_private +{ + +// We store a pointer to this class in the ProcessWindows, so that we don't expose Windows +// OS specific types and implementation details from a public header file. +class ProcessWindowsData +{ + public: + ProcessWindowsData(bool stop_at_entry) + : m_stop_at_entry(stop_at_entry) + , m_initial_stop_event(nullptr) + , m_initial_stop_received(false) + { + m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); + } + + ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } + + lldb_private::Error m_launch_error; + lldb_private::DebuggerThreadSP m_debugger; + StopInfoSP m_pending_stop_info; + HANDLE m_initial_stop_event; + bool m_stop_at_entry; + bool m_initial_stop_received; + std::map m_new_threads; + std::set m_exited_threads; +}; +} +//------------------------------------------------------------------------------ +// Static functions. + +ProcessSP +ProcessWindowsLive::CreateInstance(lldb::TargetSP target_sp, Listener &listener, const FileSpec *) +{ + return ProcessSP(new ProcessWindowsLive(target_sp, listener)); +} + +void +ProcessWindowsLive::Initialize() +{ + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() + { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); + }); +} + +//------------------------------------------------------------------------------ +// Constructors and destructors. + +ProcessWindowsLive::ProcessWindowsLive(lldb::TargetSP target_sp, Listener &listener) + : lldb_private::ProcessWindows(target_sp, listener) +{ +} + +ProcessWindowsLive::~ProcessWindowsLive() +{ +} + +void +ProcessWindowsLive::Terminate() +{ +} + +lldb_private::ConstString +ProcessWindowsLive::GetPluginNameStatic() +{ + static ConstString g_name("windows"); + return g_name; +} + +const char * +ProcessWindowsLive::GetPluginDescriptionStatic() +{ + return "Process plugin for Windows"; +} + +Error +ProcessWindowsLive::EnableBreakpointSite(BreakpointSite *bp_site) +{ + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite called with bp_site 0x%p " + "(id=%d, addr=0x%x)", + bp_site->GetID(), bp_site->GetLoadAddress()); + + Error error = EnableSoftwareBreakpoint(bp_site); + if (!error.Success()) + { + WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite failed. %s", error.AsCString()); + } + return error; +} + +Error +ProcessWindowsLive::DisableBreakpointSite(BreakpointSite *bp_site) +{ + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite called with bp_site 0x%p " + "(id=%d, addr=0x%x)", + bp_site->GetID(), bp_site->GetLoadAddress()); + + Error error = DisableSoftwareBreakpoint(bp_site); + + if (!error.Success()) + { + WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite failed. %s", error.AsCString()); + } + return error; +} + +bool +ProcessWindowsLive::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) +{ + // Add all the threads that were previously running and for which we did not detect a thread + // exited event. + int new_size = 0; + int continued_threads = 0; + int exited_threads = 0; + int new_threads = 0; + + for (ThreadSP old_thread : old_thread_list.Threads()) + { + lldb::tid_t old_thread_id = old_thread->GetID(); + auto exited_thread_iter = m_session_data->m_exited_threads.find(old_thread_id); + if (exited_thread_iter == m_session_data->m_exited_threads.end()) + { + new_thread_list.AddThread(old_thread); + ++new_size; + ++continued_threads; + WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u was running and is still running.", + old_thread_id); + } + else + { + WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u was running and has exited.", + old_thread_id); + ++exited_threads; + } + } + + // Also add all the threads that are new since the last time we broke into the debugger. + for (const auto &thread_info : m_session_data->m_new_threads) + { + ThreadSP thread(new TargetThreadWindowsLive(*this, thread_info.second)); + thread->SetID(thread_info.first); + new_thread_list.AddThread(thread); + ++new_size; + ++new_threads; + WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u is new since last update.", thread_info.first); + } + + WINLOG_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - %d new threads, %d old threads, %d exited threads.", + new_threads, continued_threads, exited_threads); + + m_session_data->m_new_threads.clear(); + m_session_data->m_exited_threads.clear(); + + return new_size > 0; +} + +Error +ProcessWindowsLive::DoLaunch(Module *exe_module, + ProcessLaunchInfo &launch_info) +{ + // Even though m_session_data is accessed here, it is before a debugger thread has been + // kicked off. So there's no race conditions, and it shouldn't be necessary to acquire + // the mutex. + + Error result; + if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) + { + StreamString stream; + stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can only be used for debug launches.", + launch_info.GetExecutableFile().GetPath().c_str()); + std::string message = stream.GetString(); + result.SetErrorString(message.c_str()); + + WINERR_IFALL(WINDOWS_LOG_PROCESS, message.c_str()); + return result; + } + + bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); + m_session_data.reset(new ProcessWindowsData(stop_at_entry)); + + SetPrivateState(eStateLaunching); + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); + m_session_data->m_debugger.reset(new DebuggerThread(delegate)); + DebuggerThreadSP debugger = m_session_data->m_debugger; + + // Kick off the DebugLaunch asynchronously and wait for it to complete. + result = debugger->DebugLaunch(launch_info); + if (result.Fail()) + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", + launch_info.GetExecutableFile().GetPath().c_str(), result.AsCString()); + return result; + } + + HostProcess process; + Error error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", + launch_info.GetExecutableFile().GetPath().c_str(), error.AsCString()); + return error; + } + + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'", + launch_info.GetExecutableFile().GetPath().c_str()); + + // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state + // should already be set to eStateStopped as a result of hitting the initial breakpoint. If + // it was not set, the breakpoint should have already been resumed from and the private state + // should already be eStateRunning. + launch_info.SetProcessID(process.GetProcessId()); + SetID(process.GetProcessId()); + + return result; +} + +Error +ProcessWindowsLive::DoAttachToProcessWithID(lldb::pid_t pid, const ProcessAttachInfo &attach_info) +{ + m_session_data.reset(new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); + + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); + DebuggerThreadSP debugger(new DebuggerThread(delegate)); + + m_session_data->m_debugger = debugger; + + DWORD process_id = static_cast(pid); + Error error = debugger->DebugAttach(process_id, attach_info); + if (error.Fail()) + { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, + "DoAttachToProcessWithID encountered an error occurred initiating the asynchronous attach. %s", + error.AsCString()); + return error; + } + + HostProcess process; + error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) + { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, + "DoAttachToProcessWithID encountered an error waiting for the debugger to connect. %s", + error.AsCString()); + return error; + } + + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID successfully attached to process with pid=%u", + process_id); + + // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state + // should already be set to eStateStopped as a result of hitting the initial breakpoint. If + // it was not set, the breakpoint should have already been resumed from and the private state + // should already be eStateRunning. + SetID(process.GetProcessId()); + return error; +} + +Error +ProcessWindowsLive::WaitForDebuggerConnection(DebuggerThreadSP debugger, HostProcess &process) +{ + Error result; + WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection Waiting for loader breakpoint."); + + // Block this function until we receive the initial stop from the process. + if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0) + { + WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection hit loader breakpoint, returning."); + + process = debugger->GetProcess(); + return m_session_data->m_launch_error; + } + else + return Error(::GetLastError(), eErrorTypeWin32); +} + +Error +ProcessWindowsLive::DoResume() +{ + llvm::sys::ScopedLock lock(m_mutex); + Error error; + + StateType private_state = GetPrivateState(); + if (private_state == eStateStopped || private_state == eStateCrashed) + { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoResume called for process %I64u while state is %u. Resuming...", + m_session_data->m_debugger->GetProcess().GetProcessId(), GetPrivateState()); + + ExceptionRecordSP active_exception = + m_session_data->m_debugger->GetActiveException().lock(); + if (active_exception) + { + // Resume the process and continue processing debug events. Mask + // the exception so that from the process's view, there is no + // indication that anything happened. + m_session_data->m_debugger->ContinueAsyncException( + ExceptionResult::MaskException); + } + + WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_THREAD, "DoResume resuming %u threads.", + m_thread_list.GetSize()); + + for (int i = 0; i < m_thread_list.GetSize(); ++i) + { + auto thread = std::static_pointer_cast( + m_thread_list.GetThreadAtIndex(i)); + thread->DoResume(); + } + + SetPrivateState(eStateRunning); + } + else + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoResume called for process %I64u but state is %u. Returning...", + m_session_data->m_debugger->GetProcess().GetProcessId(), GetPrivateState()); + } + return error; +} + + +//------------------------------------------------------------------------------ +// ProcessInterface protocol. + +lldb_private::ConstString +ProcessWindowsLive::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ProcessWindowsLive::GetPluginVersion() +{ + return 1; +} + +Error +ProcessWindowsLive::DoDetach(bool keep_stopped) +{ + DebuggerThreadSP debugger_thread; + StateType private_state; + { + // Acquire the lock only long enough to get the DebuggerThread. + // StopDebugging() will trigger a call back into ProcessWindows which + // will also acquire the lock. Thus we have to release the lock before + // calling StopDebugging(). + llvm::sys::ScopedLock lock(m_mutex); + + private_state = GetPrivateState(); + + if (!m_session_data) + { + WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDetach called while state = %u, but there is no active session.", + private_state); + return Error(); + } + + debugger_thread = m_session_data->m_debugger; + } + + Error error; + if (private_state != eStateExited && private_state != eStateDetached) + { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDetach called for process %I64u while state = %u. Detaching...", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); + error = debugger_thread->StopDebugging(false); + if (error.Success()) + { + SetPrivateState(eStateDetached); + } + + // By the time StopDebugging returns, there is no more debugger thread, so + // we can be assured that no other thread will race for the session data. + m_session_data.reset(); + } + else + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, + "DoDetach called for process %I64u while state = %u, but cannot destroy in this state.", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); + } + + return error; +} + +Error +ProcessWindowsLive::DoDestroy() +{ + DebuggerThreadSP debugger_thread; + StateType private_state; + { + // Acquire this lock inside an inner scope, only long enough to get the DebuggerThread. + // StopDebugging() will trigger a call back into ProcessWindows which will acquire the lock + // again, so we need to not deadlock. + llvm::sys::ScopedLock lock(m_mutex); + + private_state = GetPrivateState(); + + if (!m_session_data) + { + WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called while state = %u, but there is no active session.", + private_state); + return Error(); + } + + debugger_thread = m_session_data->m_debugger; + } + + Error error; + if (private_state != eStateExited && private_state != eStateDetached) + { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called for process %I64u while state = %u. Shutting down...", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); + error = debugger_thread->StopDebugging(true); + + // By the time StopDebugging returns, there is no more debugger thread, so + // we can be assured that no other thread will race for the session data. + m_session_data.reset(); + } + else + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, + "DoDestroy called for process %I64u while state = %u, but cannot destroy in this state.", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state); + } + + return error; +} + +void +ProcessWindowsLive::RefreshStateAfterStop() +{ + llvm::sys::ScopedLock lock(m_mutex); + + if (!m_session_data) + { + WINWARN_IFALL(WINDOWS_LOG_PROCESS, "RefreshStateAfterStop called with no active session. Returning..."); + return; + } + + m_thread_list.RefreshStateAfterStop(); + + std::weak_ptr exception_record = m_session_data->m_debugger->GetActiveException(); + ExceptionRecordSP active_exception = exception_record.lock(); + if (!active_exception) + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "RefreshStateAfterStop called for process %I64u but there is no " + "active exception. Why is the process stopped?", + m_session_data->m_debugger->GetProcess().GetProcessId()); + return; + } + + StopInfoSP stop_info; + m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID()); + ThreadSP stop_thread = m_thread_list.GetSelectedThread(); + if (!stop_thread) + return; + + RegisterContextSP register_context = stop_thread->GetRegisterContext(); + + // The current EIP is AFTER the BP opcode, which is one byte. + uint64_t pc = register_context->GetPC() - 1; + if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT) + { + BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); + + if (site) + { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "RefreshStateAfterStop detected breakpoint in process %I64u at " + "address 0x%I64x with breakpoint site %d", + m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID()); + + if (site->ValidForThisThread(stop_thread.get())) + { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.", + site->GetID(), stop_thread->GetID()); + + stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( + *stop_thread, site->GetID()); + register_context->SetPC(pc); + } + else + { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "Breakpoint site %d is not valid for this thread, creating empty stop info.", + site->GetID()); + } + } + stop_thread->SetStopInfo(stop_info); + } + else if (active_exception->GetExceptionCode() == EXCEPTION_SINGLE_STEP) + { + stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); + stop_thread->SetStopInfo(stop_info); + WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u", + stop_thread->GetID()); + } + else + { + std::string desc; + llvm::raw_string_ostream desc_stream(desc); + desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8) + << " encountered at address " << llvm::format_hex(pc, 8); + stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str()); + stop_thread->SetStopInfo(stop_info); + WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str()); + } +} + +bool +ProcessWindowsLive::IsAlive() +{ + StateType state = GetPrivateState(); + switch (state) + { + case eStateCrashed: + case eStateDetached: + case eStateUnloaded: + case eStateExited: + case eStateInvalid: + return false; + default: + return true; + } +} + +Error +ProcessWindowsLive::DoHalt(bool &caused_stop) +{ + Error error; + StateType state = GetPrivateState(); + if (state == eStateStopped) + caused_stop = false; + else + { + llvm::sys::ScopedLock lock(m_mutex); + caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess().GetNativeProcess().GetSystemHandle()); + if (!caused_stop) + { + error.SetError(::GetLastError(), eErrorTypeWin32); + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoHalt called DebugBreakProcess, but it failed with error %u", + error.GetError()); + } + } + return error; +} + +void +ProcessWindowsLive::DidLaunch() +{ + ArchSpec arch_spec; + DidAttach(arch_spec); +} + +void +ProcessWindowsLive::DidAttach(ArchSpec &arch_spec) +{ + llvm::sys::ScopedLock lock(m_mutex); + + // The initial stop won't broadcast the state change event, so account for that here. + if (m_session_data && GetPrivateState() == eStateStopped && m_session_data->m_stop_at_entry) + RefreshStateAfterStop(); +} + +size_t +ProcessWindowsLive::DoReadMemory(lldb::addr_t vm_addr, + void *buf, + size_t size, + Error &error) +{ + llvm::sys::ScopedLock lock(m_mutex); + + if (!m_session_data) + return 0; + + WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory attempting to read %u bytes from address 0x%I64x", size, vm_addr); + + HostProcess process = m_session_data->m_debugger->GetProcess(); + void *addr = reinterpret_cast(vm_addr); + SIZE_T bytes_read = 0; + if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, buf, size, &bytes_read)) + { + error.SetError(GetLastError(), eErrorTypeWin32); + WINERR_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory failed with error code %u", error.GetError()); + } + return bytes_read; +} + +size_t +ProcessWindowsLive::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) +{ + llvm::sys::ScopedLock lock(m_mutex); + WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, vm_addr); + + if (!m_session_data) + { + WINERR_IFANY(WINDOWS_LOG_MEMORY, "DoWriteMemory cannot write, there is no active debugger connection."); + return 0; + } + + HostProcess process = m_session_data->m_debugger->GetProcess(); + void *addr = reinterpret_cast(vm_addr); + SIZE_T bytes_written = 0; + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + if (WriteProcessMemory(handle, addr, buf, size, &bytes_written)) + FlushInstructionCache(handle, addr, bytes_written); + else + { + error.SetError(GetLastError(), eErrorTypeWin32); + WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory failed with error code %u", error.GetError()); + } + return bytes_written; +} + +Error +ProcessWindowsLive::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info) +{ + Error error; + llvm::sys::ScopedLock lock(m_mutex); + + if (!m_session_data) + { + error.SetErrorString("GetMemoryRegionInfo called with no debugging session."); + WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString()); + return error; + } + + HostProcess process = m_session_data->m_debugger->GetProcess(); + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + if (handle == nullptr || handle == LLDB_INVALID_PROCESS) + { + error.SetErrorString("GetMemoryRegionInfo called with an invalid target process."); + WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString()); + return error; + } + + WINLOG_IFALL(WINDOWS_LOG_MEMORY, "GetMemoryRegionInfo getting info for address 0x%I64x", vm_addr); + + void *addr = reinterpret_cast(vm_addr); + MEMORY_BASIC_INFORMATION mem_info = {0}; + SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); + if (result == 0) + { + error.SetError(::GetLastError(), eErrorTypeWin32); + WINERR_IFALL(WINDOWS_LOG_MEMORY, + "VirtualQueryEx returned error %u while getting memory region info for address 0x%I64x", + error.GetError(), vm_addr); + return error; + } + bool readable = !(mem_info.Protect & PAGE_NOACCESS); + bool executable = mem_info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + bool writable = mem_info.Protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READWRITE | PAGE_WRITECOPY); + info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); + info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); + info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); + error.SetError(::GetLastError(), eErrorTypeWin32); + WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address 0x%I64u: readable=%s, executable=%s, writable=%s", + BOOL_STR(readable), BOOL_STR(executable), BOOL_STR(writable)); + return error; +} + +bool +ProcessWindowsLive::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) +{ + if (plugin_specified_by_name) + return true; + + // For now we are just making sure the file exists for a given module + ModuleSP exe_module_sp(target_sp->GetExecutableModule()); + if (exe_module_sp.get()) + return exe_module_sp->GetFileSpec().Exists(); + // However, if there is no executable module, we return true since we might be preparing to attach. + return true; +} + +void +ProcessWindowsLive::OnExitProcess(uint32_t exit_code) +{ + // No need to acquire the lock since m_session_data isn't accessed. + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Process %u exited with code %u", GetID(), exit_code); + + TargetSP target = m_target_sp.lock(); + if (target) + { + ModuleSP executable_module = target->GetExecutableModule(); + ModuleList unloaded_modules; + unloaded_modules.Append(executable_module); + target->ModulesDidUnload(unloaded_modules, true); + } + + SetProcessExitStatus(nullptr, GetID(), true, 0, exit_code); + SetPrivateState(eStateExited); +} + +void +ProcessWindowsLive::OnDebuggerConnected(lldb::addr_t image_base) +{ + DebuggerThreadSP debugger = m_session_data->m_debugger; + + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Debugger connected to process %I64u. Image base = 0x%I64x", + debugger->GetProcess().GetProcessId(), image_base); + + ModuleSP module = GetTarget().GetExecutableModule(); + if (!module) + { + // During attach, we won't have the executable module, so find it now. + const DWORD pid = debugger->GetProcess().GetProcessId(); + const std::string file_name = GetProcessExecutableName(pid); + if (file_name.empty()) + { + return; + } + + FileSpec executable_file(file_name, true); + ModuleSpec module_spec(executable_file); + Error error; + module = GetTarget().GetSharedModule(module_spec, &error); + if (!module) + { + return; + } + + GetTarget().SetExecutableModule(module, false); + } + + bool load_addr_changed; + module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed); + + ModuleList loaded_modules; + loaded_modules.Append(module); + GetTarget().ModulesDidLoad(loaded_modules); + + // Add the main executable module to the list of pending module loads. We can't call + // GetTarget().ModulesDidLoad() here because we still haven't returned from DoLaunch() / DoAttach() yet + // so the target may not have set the process instance to `this` yet. + llvm::sys::ScopedLock lock(m_mutex); + const HostThreadWindows &wmain_thread = debugger->GetMainThread().GetNativeThread(); + m_session_data->m_new_threads[wmain_thread.GetThreadId()] = debugger->GetMainThread(); +} + +ExceptionResult +ProcessWindowsLive::OnDebugException(bool first_chance, const ExceptionRecord &record) +{ + llvm::sys::ScopedLock lock(m_mutex); + + // FIXME: Without this check, occasionally when running the test suite there is + // an issue where m_session_data can be null. It's not clear how this could happen + // but it only surfaces while running the test suite. In order to properly diagnose + // this, we probably need to first figure allow the test suite to print out full + // lldb logs, and then add logging to the process plugin. + if (!m_session_data) + { + WINERR_IFANY(WINDOWS_LOG_EXCEPTION, + "Debugger thread reported exception 0x%x at address 0x%I64x, but there is no session.", + record.GetExceptionCode(), record.GetExceptionAddress()); + return ExceptionResult::SendToApplication; + } + + if (!first_chance) + { + // Any second chance exception is an application crash by definition. + SetPrivateState(eStateCrashed); + } + + ExceptionResult result = ExceptionResult::SendToApplication; + switch (record.GetExceptionCode()) + { + case EXCEPTION_BREAKPOINT: + // Handle breakpoints at the first chance. + result = ExceptionResult::BreakInDebugger; + + if (!m_session_data->m_initial_stop_received) + { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, + "Hit loader breakpoint at address 0x%I64x, setting initial stop event.", + record.GetExceptionAddress()); + m_session_data->m_initial_stop_received = true; + ::SetEvent(m_session_data->m_initial_stop_event); + } + else + { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, + "Hit non-loader breakpoint at address 0x%I64x.", + record.GetExceptionAddress()); + } + SetPrivateState(eStateStopped); + break; + case EXCEPTION_SINGLE_STEP: + result = ExceptionResult::BreakInDebugger; + SetPrivateState(eStateStopped); + break; + default: + WINLOG_IFANY(WINDOWS_LOG_EXCEPTION, + "Debugger thread reported exception 0x%x at address 0x%I64x (first_chance=%s)", + record.GetExceptionCode(), record.GetExceptionAddress(), BOOL_STR(first_chance)); + // For non-breakpoints, give the application a chance to handle the exception first. + if (first_chance) + result = ExceptionResult::SendToApplication; + else + result = ExceptionResult::BreakInDebugger; + } + + return result; +} + +void +ProcessWindowsLive::OnCreateThread(const HostThread &new_thread) +{ + llvm::sys::ScopedLock lock(m_mutex); + const HostThreadWindows &wnew_thread = new_thread.GetNativeThread(); + m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread; +} + +void +ProcessWindowsLive::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) +{ + llvm::sys::ScopedLock lock(m_mutex); + + // On a forced termination, we may get exit thread events after the session + // data has been cleaned up. + if (!m_session_data) + return; + + // A thread may have started and exited before the debugger stopped allowing a refresh. + // Just remove it from the new threads list in that case. + auto iter = m_session_data->m_new_threads.find(thread_id); + if (iter != m_session_data->m_new_threads.end()) + m_session_data->m_new_threads.erase(iter); + else + m_session_data->m_exited_threads.insert(thread_id); +} + +void +ProcessWindowsLive::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) +{ + // Confusingly, there is no Target::AddSharedModule. Instead, calling GetSharedModule() with + // a new module will add it to the module list and return a corresponding ModuleSP. + Error error; + ModuleSP module = GetTarget().GetSharedModule(module_spec, &error); + bool load_addr_changed = false; + module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed); + + ModuleList loaded_modules; + loaded_modules.Append(module); + GetTarget().ModulesDidLoad(loaded_modules); +} + +void +ProcessWindowsLive::OnUnloadDll(lldb::addr_t module_addr) +{ + Address resolved_addr; + if (GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) + { + ModuleSP module = resolved_addr.GetModule(); + if (module) + { + ModuleList unloaded_modules; + unloaded_modules.Append(module); + GetTarget().ModulesDidUnload(unloaded_modules, false); + } + } +} + +void +ProcessWindowsLive::OnDebugString(const std::string &string) +{ +} + +void +ProcessWindowsLive::OnDebuggerError(const Error &error, uint32_t type) +{ + llvm::sys::ScopedLock lock(m_mutex); + + if (m_session_data->m_initial_stop_received) + { + // This happened while debugging. Do we shutdown the debugging session, try to continue, + // or do something else? + WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred during debugging. Unexpected behavior may result. %s", + error.GetError(), error.AsCString()); + } + else + { + // If we haven't actually launched the process yet, this was an error launching the + // process. Set the internal error and signal the initial stop event so that the DoLaunch + // method wakes up and returns a failure. + m_session_data->m_launch_error = error; + ::SetEvent(m_session_data->m_initial_stop_event); + WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred launching the process before the initial stop. %s", + error.GetError(), error.AsCString()); + return; + } +} Index: source/Plugins/Process/Windows/Live/ProcessWindowsLog.h =================================================================== --- source/Plugins/Process/Windows/Live/ProcessWindowsLog.h +++ /dev/null @@ -1,96 +0,0 @@ -//===-- ProcessWindowsLog.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_ProcessWindowsLog_h_ -#define liblldb_ProcessWindowsLog_h_ - -#include "lldb/Core/Log.h" - -#define WINDOWS_LOG_VERBOSE (1u << 0) -#define WINDOWS_LOG_PROCESS (1u << 1) // Log process operations -#define WINDOWS_LOG_EXCEPTION (1u << 1) // Log exceptions -#define WINDOWS_LOG_THREAD (1u << 2) // Log thread operations -#define WINDOWS_LOG_MEMORY (1u << 3) // Log memory reads/writes calls -#define WINDOWS_LOG_BREAKPOINTS (1u << 4) // Log breakpoint operations -#define WINDOWS_LOG_STEP (1u << 5) // Log step operations -#define WINDOWS_LOG_REGISTERS (1u << 6) // Log register operations -#define WINDOWS_LOG_EVENT (1u << 7) // Low level debug events -#define WINDOWS_LOG_ALL (UINT32_MAX) - -enum class LogMaskReq -{ - All, - Any -}; - -class ProcessWindowsLog -{ - static const char *m_pluginname; - -public: - // --------------------------------------------------------------------- - // Public Static Methods - // --------------------------------------------------------------------- - static void - Initialize(); - - static void - Terminate(); - - static void - RegisterPluginName(const char *pluginName) - { - m_pluginname = pluginName; - } - - static void - RegisterPluginName(lldb_private::ConstString pluginName) - { - m_pluginname = pluginName.GetCString(); - } - - static bool - TestLogFlags(uint32_t mask, LogMaskReq req); - - static lldb_private::Log * - GetLog(); - - 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); -}; - -#define WINLOGF_IF(Flags, Req, Method, ...) \ - { \ - if (ProcessWindowsLog::TestLogFlags(Flags, Req)) \ - { \ - Log *log = ProcessWindowsLog::GetLog(); \ - if (log) \ - log->Method(__VA_ARGS__); \ - } \ - } - -#define WINLOG_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Printf, __VA_ARGS__) -#define WINLOG_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Printf, __VA_ARGS__) -#define WINLOGV_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Verbose, __VA_ARGS__) -#define WINLOGV_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Verbose, __VA_ARGS__) -#define WINLOGD_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Debug, __VA_ARGS__) -#define WINLOGD_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Debug, __VA_ARGS__) -#define WINERR_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Error, __VA_ARGS__) -#define WINERR_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Error, __VA_ARGS__) -#define WINWARN_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Warning, __VA_ARGS__) -#define WINWARN_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Warning, __VA_ARGS__) - -#endif // liblldb_ProcessWindowsLog_h_ Index: source/Plugins/Process/Windows/Live/ProcessWindowsLog.cpp =================================================================== --- source/Plugins/Process/Windows/Live/ProcessWindowsLog.cpp +++ /dev/null @@ -1,196 +0,0 @@ -//===-- ProcessWindowsLog.cpp -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ProcessWindowsLog.h" - -#include - -#include "lldb/Core/StreamFile.h" -#include "lldb/Interpreter/Args.h" -#include "llvm/Support/ManagedStatic.h" - -#include "ProcessWindows.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 = nullptr; - -static llvm::ManagedStatic g_once_flag; - -void -ProcessWindowsLog::Initialize() -{ - static ConstString g_name("windows"); - - std::call_once(*g_once_flag, [](){ - Log::Callbacks log_callbacks = { - DisableLog, - EnableLog, - ListLogCategories - }; - - Log::RegisterLogChannel(g_name, log_callbacks); - RegisterPluginName(g_name); - }); -} - -void -ProcessWindowsLog::Terminate() -{ -} - -Log * -ProcessWindowsLog::GetLog() -{ - return (g_log_enabled) ? g_log : nullptr; -} - -bool -ProcessWindowsLog::TestLogFlags(uint32_t mask, LogMaskReq req) -{ - Log *log = GetLog(); - if (!log) - return false; - - uint32_t log_mask = log->GetMask().Get(); - if (req == LogMaskReq::All) - return ((log_mask & mask) == mask); - else - return (log_mask & mask); -} - -static uint32_t -GetFlagBits(const char *arg) -{ - if (::strcasecmp(arg, "all") == 0 ) return WINDOWS_LOG_ALL; - else if (::strcasecmp(arg, "break") == 0 ) return WINDOWS_LOG_BREAKPOINTS; - else if (::strcasecmp(arg, "event") == 0 ) return WINDOWS_LOG_EVENT; - else if (::strcasecmp(arg, "exception") == 0 ) return WINDOWS_LOG_EXCEPTION; - else if (::strcasecmp(arg, "memory") == 0 ) return WINDOWS_LOG_MEMORY; - else if (::strcasecmp(arg, "process") == 0 ) return WINDOWS_LOG_PROCESS; - else if (::strcasecmp(arg, "registers") == 0 ) return WINDOWS_LOG_REGISTERS; - else if (::strcasecmp(arg, "step") == 0 ) return WINDOWS_LOG_STEP; - else if (::strcasecmp(arg, "thread") == 0 ) return WINDOWS_LOG_THREAD; - else if (::strcasecmp(arg, "verbose") == 0 ) return WINDOWS_LOG_VERBOSE; - return 0; -} - -void -ProcessWindowsLog::DisableLog(const char **args, Stream *feedback_strm) -{ - Log *log (GetLog()); - if (log) - { - uint32_t flag_bits = 0; - - if (args[0] != nullptr) - { - 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; - log->SetStream(lldb::StreamSP()); - } - } - - return; -} - -Log * -ProcessWindowsLog::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 = WINDOWS_LOG_ALL; - g_log->GetMask().Reset(flag_bits); - g_log->GetOptions().Reset(log_options); - g_log_enabled = true; - } - return g_log; -} - -void -ProcessWindowsLog::ListLogCategories(Stream *strm) -{ - strm->Printf("Logging categories for '%s':\n" - " all - turn on all available logging categories\n" - " break - log breakpoints\n" - " event - log low level debugger events\n" - " exception - log exception information\n" - " memory - log memory reads and writes\n" - " process - log process events and activities\n" - " registers - log register read/writes\n" - " thread - log thread events and activities\n" - " step - log step related activities\n" - " verbose - enable verbose logging\n", - ProcessWindowsLog::m_pluginname); -} - -const char *ProcessWindowsLog::m_pluginname = ""; Index: source/Plugins/Process/Windows/Live/RegisterContextWindows.h =================================================================== --- source/Plugins/Process/Windows/Live/RegisterContextWindows.h +++ /dev/null @@ -1,69 +0,0 @@ -//===-- RegisterContextWindows.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_H_ -#define liblldb_RegisterContextWindows_H_ - -#include "lldb/lldb-forward.h" -#include "lldb/Target/RegisterContext.h" - -namespace lldb_private -{ - -class Thread; - -class RegisterContextWindows : public lldb_private::RegisterContext -{ - public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindows(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindows(); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - void InvalidateAllRegisters() 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; - - protected: - bool CacheAllRegisterValues(); - - CONTEXT m_context; - - private: - bool m_context_stale; -}; -} - -#endif // #ifndef liblldb_RegisterContextPOSIX_x86_H_ Index: source/Plugins/Process/Windows/Live/RegisterContextWindows.cpp =================================================================== --- source/Plugins/Process/Windows/Live/RegisterContextWindows.cpp +++ /dev/null @@ -1,155 +0,0 @@ -//===-- RegisterContextWindows.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/lldb-private-types.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" - -#include "ProcessWindowsLog.h" -#include "RegisterContextWindows.h" -#include "TargetThreadWindows.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -const DWORD kWinContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - -//------------------------------------------------------------------ -// Constructors and Destructors -//------------------------------------------------------------------ -RegisterContextWindows::RegisterContextWindows(Thread &thread, uint32_t concrete_frame_idx) - : RegisterContext(thread, concrete_frame_idx) - , m_context() - , m_context_stale(true) -{ -} - -RegisterContextWindows::~RegisterContextWindows() -{ -} - -void -RegisterContextWindows::InvalidateAllRegisters() -{ - m_context_stale = true; -} - -bool -RegisterContextWindows::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) -{ - if (!CacheAllRegisterValues()) - return false; - if (data_sp->GetByteSize() < sizeof(m_context)) - { - data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); - } - memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context)); - return true; -} - -bool -RegisterContextWindows::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) -{ - assert(data_sp->GetByteSize() >= sizeof(m_context)); - memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context)); - - TargetThreadWindows &wthread = static_cast(m_thread); - if (!::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context)) - return false; - - return true; -} - -uint32_t -RegisterContextWindows::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::NumSupportedHardwareBreakpoints() -{ - // Support for hardware breakpoints not yet implemented. - return 0; -} - -uint32_t -RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) -{ - return 0; -} - -bool -RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) -{ - return false; -} - -uint32_t -RegisterContextWindows::NumSupportedHardwareWatchpoints() -{ - // Support for hardware watchpoints not yet implemented. - return 0; -} - -uint32_t -RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) -{ - return 0; -} - -bool -RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextWindows::HardwareSingleStep(bool enable) -{ - return false; -} - -bool -RegisterContextWindows::CacheAllRegisterValues() -{ - if (!m_context_stale) - return true; - - TargetThreadWindows &wthread = static_cast(m_thread); - memset(&m_context, 0, sizeof(m_context)); - m_context.ContextFlags = kWinContextFlags; - if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context)) - { - WINERR_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext failed with error %u while caching register values.", - ::GetLastError()); - return false; - } - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext successfully updated the register values.", ::GetLastError()); - m_context_stale = false; - return true; -} Index: source/Plugins/Process/Windows/Live/TargetThreadWindows.h =================================================================== --- source/Plugins/Process/Windows/Live/TargetThreadWindows.h +++ /dev/null @@ -1,55 +0,0 @@ -//===-- TargetThreadWindows.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_Plugins_Process_Windows_TargetThreadWindows_H_ -#define liblldb_Plugins_Process_Windows_TargetThreadWindows_H_ - -#include "ForwardDecl.h" -#include "lldb/lldb-forward.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Target/Thread.h" -class ProcessWindows; - -namespace lldb_private -{ - -class HostThread; -class StackFrame; - -class TargetThreadWindows : public lldb_private::Thread -{ - public: - TargetThreadWindows(ProcessWindows &process, const HostThread &thread); - virtual ~TargetThreadWindows(); - - // 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); - - HostThread m_host_thread; -}; -} - -#endif \ No newline at end of file Index: source/Plugins/Process/Windows/Live/TargetThreadWindows.cpp =================================================================== --- source/Plugins/Process/Windows/Live/TargetThreadWindows.cpp +++ /dev/null @@ -1,147 +0,0 @@ -//===-- TargetThreadWindows.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/Log.h" -#include "lldb/Core/Logging.h" -#include "lldb/Core/State.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 "ProcessWindowsLog.h" -#include "UnwindLLDB.h" - -#if defined(_WIN64) -#include "x64/RegisterContextWindows_x64.h" -#else -#include "x86/RegisterContextWindows_x86.h" -#endif - -using namespace lldb; -using namespace lldb_private; - -TargetThreadWindows::TargetThreadWindows(ProcessWindows &process, const HostThread &thread) - : Thread(process, thread.GetNativeThread().GetThreadId()) - , m_host_thread(thread) -{ -} - -TargetThreadWindows::~TargetThreadWindows() -{ - DestroyThread(); -} - -void -TargetThreadWindows::RefreshStateAfterStop() -{ - ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle()); - SetState(eStateStopped); - GetRegisterContext()->InvalidateIfNeeded(false); -} - -void -TargetThreadWindows::WillResume(lldb::StateType resume_state) -{ -} - -void -TargetThreadWindows::DidStop() -{ -} - -RegisterContextSP -TargetThreadWindows::GetRegisterContext() -{ - if (!m_reg_context_sp) - m_reg_context_sp = CreateRegisterContextForFrameIndex(0); - - return m_reg_context_sp; -} - -RegisterContextSP -TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) -{ - 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: -#if defined(_WIN64) - // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 -#else - m_reg_context_sp.reset(new RegisterContextWindows_x86(*this, idx)); -#endif - break; - case llvm::Triple::x86_64: -#if defined(_WIN64) - m_reg_context_sp.reset(new RegisterContextWindows_x64(*this, idx)); -#else - // LLDB is 32-bit, but the target process is 64-bit. We probably can't debug this. -#endif - default: - break; - } - } - return m_reg_context_sp; -} - -bool -TargetThreadWindows::CalculateStopInfo() -{ - 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 -TargetThreadWindows::DoResume() -{ - StateType resume_state = GetTemporaryResumeState(); - StateType current_state = GetState(); - if (resume_state == current_state) - return true; - - if (resume_state == eStateStepping) - { - uint32_t flags_index = GetRegisterContext()->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - uint64_t flags_value = GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0); - flags_value |= 0x100; // Set the trap flag on the CPU - GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value); - } - - if (resume_state == eStateStepping || resume_state == eStateRunning) - { - DWORD previous_suspend_count = 0; - HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle(); - do - { - previous_suspend_count = ::ResumeThread(thread_handle); - } while (previous_suspend_count > 0); - } - return true; -} Index: source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h @@ -0,0 +1,55 @@ +//===-- TargetThreadWindowsLive.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_Plugins_Process_Windows_TargetThreadWindowsLive_H_ +#define liblldb_Plugins_Process_Windows_TargetThreadWindowsLive_H_ + +#include "lldb/lldb-forward.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/Thread.h" + +#include "Plugins/Process/Windows/Common/TargetThreadWindows.h" + +namespace lldb_private +{ +class ProcessWindows; +class HostThread; +class StackFrame; + +class TargetThreadWindowsLive : public lldb_private::TargetThreadWindows +{ + public: + TargetThreadWindowsLive(ProcessWindows &process, const HostThread &thread); + virtual ~TargetThreadWindowsLive(); + + // 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); + + HostThread m_host_thread; +}; +} + +#endif Index: source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp @@ -0,0 +1,147 @@ +//===-- TargetThreadWindowsLive.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/Log.h" +#include "lldb/Core/Logging.h" +#include "lldb/Core/State.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 "TargetThreadWindowsLive.h" +#include "ProcessWindows.h" +#include "ProcessWindowsLog.h" +#include "UnwindLLDB.h" + +#if defined(_WIN64) +#include "x64/RegisterContextWindowsLive_x64.h" +#else +#include "x86/RegisterContextWindowsLive_x86.h" +#endif + +using namespace lldb; +using namespace lldb_private; + +TargetThreadWindowsLive::TargetThreadWindowsLive(ProcessWindows &process, const HostThread &thread) + : TargetThreadWindows(process, thread) + , m_host_thread(thread) +{ +} + +TargetThreadWindowsLive::~TargetThreadWindowsLive() +{ + DestroyThread(); +} + +void +TargetThreadWindowsLive::RefreshStateAfterStop() +{ + ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle()); + SetState(eStateStopped); + GetRegisterContext()->InvalidateIfNeeded(false); +} + +void +TargetThreadWindowsLive::WillResume(lldb::StateType resume_state) +{ +} + +void +TargetThreadWindowsLive::DidStop() +{ +} + +RegisterContextSP +TargetThreadWindowsLive::GetRegisterContext() +{ + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrameIndex(0); + + return m_reg_context_sp; +} + +RegisterContextSP +TargetThreadWindowsLive::CreateRegisterContextForFrame(StackFrame *frame) +{ + return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex()); +} + +RegisterContextSP +TargetThreadWindowsLive::CreateRegisterContextForFrameIndex(uint32_t idx) +{ + if (!m_reg_context_sp) + { + ArchSpec arch = HostInfo::GetArchitecture(); + switch (arch.GetMachine()) + { + case llvm::Triple::x86: +#if defined(_WIN64) + // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 +#else + m_reg_context_sp.reset(new RegisterContextWindowsLive_x86(*this, idx)); +#endif + break; + case llvm::Triple::x86_64: +#if defined(_WIN64) + m_reg_context_sp.reset(new RegisterContextWindowsLive_x64(*this, idx)); +#else + // LLDB is 32-bit, but the target process is 64-bit. We probably can't debug this. +#endif + default: + break; + } + } + return m_reg_context_sp; +} + +bool +TargetThreadWindowsLive::CalculateStopInfo() +{ + SetStopInfo(m_stop_info_sp); + return true; +} + +Unwind * +TargetThreadWindowsLive::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 +TargetThreadWindowsLive::DoResume() +{ + StateType resume_state = GetTemporaryResumeState(); + StateType current_state = GetState(); + if (resume_state == current_state) + return true; + + if (resume_state == eStateStepping) + { + uint32_t flags_index = GetRegisterContext()->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + uint64_t flags_value = GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0); + flags_value |= 0x100; // Set the trap flag on the CPU + GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value); + } + + if (resume_state == eStateStepping || resume_state == eStateRunning) + { + DWORD previous_suspend_count = 0; + HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle(); + do + { + previous_suspend_count = ::ResumeThread(thread_handle); + } while (previous_suspend_count > 0); + } + return true; +} Index: source/Plugins/Process/Windows/Live/x64/RegisterContextWindows_x64.h =================================================================== --- source/Plugins/Process/Windows/Live/x64/RegisterContextWindows_x64.h +++ /dev/null @@ -1,48 +0,0 @@ -//===-- RegisterContextWindows_x64.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_x64_H_ -#define liblldb_RegisterContextWindows_x64_H_ - -#include "lldb/lldb-forward.h" -#include "RegisterContextWindows.h" - -namespace lldb_private -{ - -class Thread; - -class RegisterContextWindows_x64 : public RegisterContextWindows -{ - public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindows_x64(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindows_x64(); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - 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; -}; -} - -#endif // #ifndef liblldb_RegisterContextPOSIX_x64_H_ Index: source/Plugins/Process/Windows/Live/x64/RegisterContextWindows_x64.cpp =================================================================== --- source/Plugins/Process/Windows/Live/x64/RegisterContextWindows_x64.cpp +++ /dev/null @@ -1,323 +0,0 @@ -//===-- RegisterContextWindows_x64.cpp --------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/lldb-private-types.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_x64.h" -#include "TargetThreadWindows.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -#define DEFINE_GPR(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatHexUppercase -#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatBinary - -namespace -{ - -// This enum defines the layout of the global RegisterInfo array. This is necessary because -// lldb register sets are defined in terms of indices into the register array. As such, the -// order of RegisterInfos defined in global registers array must match the order defined here. -// When defining the register set layouts, these values can appear in an arbitrary order, and that -// determines the order that register values are displayed in a dump. -enum RegisterIndex -{ - eRegisterIndexRax, - eRegisterIndexRbx, - eRegisterIndexRcx, - eRegisterIndexRdx, - eRegisterIndexRdi, - eRegisterIndexRsi, - eRegisterIndexR8, - eRegisterIndexR9, - eRegisterIndexR10, - eRegisterIndexR11, - eRegisterIndexR12, - eRegisterIndexR13, - eRegisterIndexR14, - eRegisterIndexR15, - eRegisterIndexRbp, - eRegisterIndexRsp, - eRegisterIndexRip, - eRegisterIndexRflags -}; - -// Array of all register information supported by Windows x86 -RegisterInfo g_register_infos[] = { - // Macro auto defines most stuff eh_frame DWARF GENERIC - // GDB LLDB VALUE REGS INVALIDATE REGS - // ================================ ========================= ====================== ========================= - // =================== ================= ========== =============== - {DEFINE_GPR(rax, nullptr), - {dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rax_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rbx, nullptr), - {dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rbx_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rcx, nullptr), - {dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rcx_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rdx, nullptr), - {dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rdx_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rdi, nullptr), - {dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rdi_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rsi, nullptr), - {dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rsi_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r8, nullptr), - {dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r8_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r9, nullptr), - {dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r9_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r10, nullptr), - {dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r10_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r11, nullptr), - {dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r11_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r12, nullptr), - {dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r12_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r13, nullptr), - {dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r13_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r14, nullptr), - {dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r14_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r15, nullptr), - {dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r15_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rbp, "fp"), - {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, lldb_rbp_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rsp, "sp"), - {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, lldb_rsp_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rip, "pc"), - {dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, lldb_rip_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR_BIN(eflags, "flags"), - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, lldb_rflags_x86_64}, - nullptr, - nullptr}, -}; - -// Array of lldb register numbers used to define the set of all General Purpose Registers -uint32_t g_gpr_reg_indices[] = {eRegisterIndexRax, eRegisterIndexRbx, eRegisterIndexRcx, eRegisterIndexRdx, - eRegisterIndexRdi, eRegisterIndexRsi, eRegisterIndexR8, eRegisterIndexR9, - eRegisterIndexR10, eRegisterIndexR11, eRegisterIndexR12, eRegisterIndexR13, - eRegisterIndexR14, eRegisterIndexR15, eRegisterIndexRbp, eRegisterIndexRsp, - eRegisterIndexRip, eRegisterIndexRflags}; - -RegisterSet g_register_sets[] = { - {"General Purpose Registers", "gpr", llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices}, -}; -} - -//------------------------------------------------------------------ -// Constructors and Destructors -//------------------------------------------------------------------ -RegisterContextWindows_x64::RegisterContextWindows_x64(Thread &thread, uint32_t concrete_frame_idx) - : RegisterContextWindows(thread, concrete_frame_idx) -{ -} - -RegisterContextWindows_x64::~RegisterContextWindows_x64() -{ -} - -size_t -RegisterContextWindows_x64::GetRegisterCount() -{ - return llvm::array_lengthof(g_register_infos); -} - -const RegisterInfo * -RegisterContextWindows_x64::GetRegisterInfoAtIndex(size_t reg) -{ - return &g_register_infos[reg]; -} - -size_t -RegisterContextWindows_x64::GetRegisterSetCount() -{ - return llvm::array_lengthof(g_register_sets); -} - -const RegisterSet * -RegisterContextWindows_x64::GetRegisterSet(size_t reg_set) -{ - return &g_register_sets[reg_set]; -} - -bool -RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) -{ - if (!CacheAllRegisterValues()) - return false; - - switch (reg_info->kinds[eRegisterKindLLDB]) - { - case lldb_rax_x86_64: - reg_value.SetUInt64(m_context.Rax); - break; - case lldb_rbx_x86_64: - reg_value.SetUInt64(m_context.Rbx); - break; - case lldb_rcx_x86_64: - reg_value.SetUInt64(m_context.Rcx); - break; - case lldb_rdx_x86_64: - reg_value.SetUInt64(m_context.Rdx); - break; - case lldb_rdi_x86_64: - reg_value.SetUInt64(m_context.Rdi); - break; - case lldb_rsi_x86_64: - reg_value.SetUInt64(m_context.Rsi); - break; - case lldb_r8_x86_64: - reg_value.SetUInt64(m_context.R8); - break; - case lldb_r9_x86_64: - reg_value.SetUInt64(m_context.R9); - break; - case lldb_r10_x86_64: - reg_value.SetUInt64(m_context.R10); - break; - case lldb_r11_x86_64: - reg_value.SetUInt64(m_context.R11); - break; - case lldb_r12_x86_64: - reg_value.SetUInt64(m_context.R12); - break; - case lldb_r13_x86_64: - reg_value.SetUInt64(m_context.R13); - break; - case lldb_r14_x86_64: - reg_value.SetUInt64(m_context.R14); - break; - case lldb_r15_x86_64: - reg_value.SetUInt64(m_context.R15); - break; - case lldb_rbp_x86_64: - reg_value.SetUInt64(m_context.Rbp); - break; - case lldb_rsp_x86_64: - reg_value.SetUInt64(m_context.Rsp); - break; - case lldb_rip_x86_64: - reg_value.SetUInt64(m_context.Rip); - break; - case lldb_rflags_x86_64: - reg_value.SetUInt64(m_context.EFlags); - break; - } - return true; -} - -bool -RegisterContextWindows_x64::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; - - switch (reg_info->kinds[eRegisterKindLLDB]) - { - case lldb_rax_x86_64: - m_context.Rax = reg_value.GetAsUInt64(); - break; - case lldb_rbx_x86_64: - m_context.Rbx = reg_value.GetAsUInt64(); - break; - case lldb_rcx_x86_64: - m_context.Rcx = reg_value.GetAsUInt64(); - break; - case lldb_rdx_x86_64: - m_context.Rdx = reg_value.GetAsUInt64(); - break; - case lldb_rdi_x86_64: - m_context.Rdi = reg_value.GetAsUInt64(); - break; - case lldb_rsi_x86_64: - m_context.Rsi = reg_value.GetAsUInt64(); - break; - case lldb_r8_x86_64: - m_context.R8 = reg_value.GetAsUInt64(); - break; - case lldb_r9_x86_64: - m_context.R9 = reg_value.GetAsUInt64(); - break; - case lldb_r10_x86_64: - m_context.R10 = reg_value.GetAsUInt64(); - break; - case lldb_r11_x86_64: - m_context.R11 = reg_value.GetAsUInt64(); - break; - case lldb_r12_x86_64: - m_context.R12 = reg_value.GetAsUInt64(); - break; - case lldb_r13_x86_64: - m_context.R13 = reg_value.GetAsUInt64(); - break; - case lldb_r14_x86_64: - m_context.R14 = reg_value.GetAsUInt64(); - break; - case lldb_r15_x86_64: - m_context.R15 = reg_value.GetAsUInt64(); - break; - case lldb_rbp_x86_64: - m_context.Rbp = reg_value.GetAsUInt64(); - break; - case lldb_rsp_x86_64: - m_context.Rsp = reg_value.GetAsUInt64(); - break; - case lldb_rip_x86_64: - m_context.Rip = reg_value.GetAsUInt64(); - break; - case lldb_rflags_x86_64: - m_context.EFlags = reg_value.GetAsUInt64(); - break; - } - - // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast(m_thread); - return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); -} Index: source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h @@ -0,0 +1,38 @@ +//===-- RegisterContextWindowsLive_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_RegisterContextWindowsLive_x86_H_ +#define liblldb_RegisterContextWindowsLive_x86_H_ + +#include "lldb/lldb-forward.h" +#include "../../Common/x86/RegisterContextWindows_x86.h" + +namespace lldb_private +{ + +class Thread; + +class RegisterContextWindowsLive_x86 : public RegisterContextWindows_x86 +{ + public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + RegisterContextWindowsLive_x86(Thread &thread, uint32_t concrete_frame_idx); + + virtual ~RegisterContextWindowsLive_x86(); + + bool ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) override; + + bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) override; +}; + +} + +#endif // #ifndef liblldb_RegisterContextWindowsLive_x86_H_ Index: source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp @@ -0,0 +1,157 @@ +//===-- RegisterContextWindowsLive_x86.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private-types.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 "ProcessWindowsLog.h" +#include "RegisterContextWindowsLive_x86.h" +#include "TargetThreadWindows.h" + +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; + +namespace lldb_private +{ + +RegisterContextWindowsLive_x86::RegisterContextWindowsLive_x86(Thread &thread, uint32_t concrete_frame_idx) + : RegisterContextWindows_x86(thread, concrete_frame_idx) +{ +} + +RegisterContextWindowsLive_x86::~RegisterContextWindowsLive_x86() +{ +} + + +bool +RegisterContextWindowsLive_x86::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) +{ + if (!CacheAllRegisterValues()) + return false; + + uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + switch (reg) + { + case lldb_eax_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EAX", m_context.Eax); + reg_value.SetUInt32(m_context.Eax); + break; + case lldb_ebx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EBX", m_context.Ebx); + reg_value.SetUInt32(m_context.Ebx); + break; + case lldb_ecx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ECX", m_context.Ecx); + reg_value.SetUInt32(m_context.Ecx); + break; + case lldb_edx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EDX", m_context.Edx); + reg_value.SetUInt32(m_context.Edx); + break; + case lldb_edi_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EDI", m_context.Edi); + reg_value.SetUInt32(m_context.Edi); + break; + case lldb_esi_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ESI", m_context.Esi); + reg_value.SetUInt32(m_context.Esi); + break; + case lldb_ebp_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EBP", m_context.Ebp); + reg_value.SetUInt32(m_context.Ebp); + break; + case lldb_esp_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ESP", m_context.Esp); + reg_value.SetUInt32(m_context.Esp); + break; + case lldb_eip_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EIP", m_context.Eip); + reg_value.SetUInt32(m_context.Eip); + break; + case lldb_eflags_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EFLAGS", m_context.EFlags); + reg_value.SetUInt32(m_context.EFlags); + break; + default: + WINWARN_IFALL(WINDOWS_LOG_REGISTERS, "Requested unknown register %u", reg); + break; + } + return true; +} + + +bool +RegisterContextWindowsLive_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; + + uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + switch (reg) + { + case lldb_eax_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EAX", reg_value.GetAsUInt32()); + m_context.Eax = reg_value.GetAsUInt32(); + break; + case lldb_ebx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBX", reg_value.GetAsUInt32()); + m_context.Ebx = reg_value.GetAsUInt32(); + break; + case lldb_ecx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ECX", reg_value.GetAsUInt32()); + m_context.Ecx = reg_value.GetAsUInt32(); + break; + case lldb_edx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDX", reg_value.GetAsUInt32()); + m_context.Edx = reg_value.GetAsUInt32(); + break; + case lldb_edi_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDI", reg_value.GetAsUInt32()); + m_context.Edi = reg_value.GetAsUInt32(); + break; + case lldb_esi_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESI", reg_value.GetAsUInt32()); + m_context.Esi = reg_value.GetAsUInt32(); + break; + case lldb_ebp_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBP", reg_value.GetAsUInt32()); + m_context.Ebp = reg_value.GetAsUInt32(); + break; + case lldb_esp_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESP", reg_value.GetAsUInt32()); + m_context.Esp = reg_value.GetAsUInt32(); + break; + case lldb_eip_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EIP", reg_value.GetAsUInt32()); + m_context.Eip = reg_value.GetAsUInt32(); + break; + case lldb_eflags_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EFLAGS", reg_value.GetAsUInt32()); + m_context.EFlags = reg_value.GetAsUInt32(); + break; + default: + WINWARN_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to unknown register %u", reg_value.GetAsUInt32(), + reg); + } + + // Physically update the registers in the target process. + TargetThreadWindows &wthread = static_cast(m_thread); + return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); +} + +} // namespace lldb_private Index: source/Plugins/Process/Windows/Live/x86/RegisterContextWindows_x86.h =================================================================== --- source/Plugins/Process/Windows/Live/x86/RegisterContextWindows_x86.h +++ /dev/null @@ -1,48 +0,0 @@ -//===-- 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 "RegisterContextWindows.h" - -namespace lldb_private -{ - -class Thread; - -class RegisterContextWindows_x86 : public RegisterContextWindows -{ - public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindows_x86(); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - 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; -}; -} - -#endif // #ifndef liblldb_RegisterContextPOSIX_x86_H_ Index: source/Plugins/Process/Windows/Live/x86/RegisterContextWindows_x86.cpp =================================================================== --- source/Plugins/Process/Windows/Live/x86/RegisterContextWindows_x86.cpp +++ /dev/null @@ -1,241 +0,0 @@ -//===-- 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/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 "ProcessWindowsLog.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_GPR(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatHexUppercase -#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatBinary - -namespace -{ - -// This enum defines the layout of the global RegisterInfo array. This is necessary because -// lldb register sets are defined in terms of indices into the register array. As such, the -// order of RegisterInfos defined in global registers array must match the order defined here. -// When defining the register set layouts, these values can appear in an arbitrary order, and that -// determines the order that register values are displayed in a dump. -enum RegisterIndex -{ - eRegisterIndexEax, - eRegisterIndexEbx, - eRegisterIndexEcx, - eRegisterIndexEdx, - eRegisterIndexEdi, - eRegisterIndexEsi, - eRegisterIndexEbp, - eRegisterIndexEsp, - eRegisterIndexEip, - eRegisterIndexEflags -}; - -// Array of all register information supported by Windows x86 -RegisterInfo g_register_infos[] = -{ -// Macro auto defines most stuff eh_frame DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS -// ============================== ======================= =================== ========================= =================== ================= ========== =============== - { DEFINE_GPR(eax, nullptr), { ehframe_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_eax_i386 }, nullptr, nullptr}, - { DEFINE_GPR(ebx, nullptr), { ehframe_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_ebx_i386 }, nullptr, nullptr}, - { DEFINE_GPR(ecx, nullptr), { ehframe_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_ecx_i386 }, nullptr, nullptr}, - { DEFINE_GPR(edx, nullptr), { ehframe_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_edx_i386 }, nullptr, nullptr}, - { DEFINE_GPR(edi, nullptr), { ehframe_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_edi_i386 }, nullptr, nullptr}, - { DEFINE_GPR(esi, nullptr), { ehframe_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_esi_i386 }, nullptr, nullptr}, - { DEFINE_GPR(ebp, "fp"), { ehframe_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, lldb_ebp_i386 }, nullptr, nullptr}, - { DEFINE_GPR(esp, "sp"), { ehframe_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, lldb_esp_i386 }, nullptr, nullptr}, - { DEFINE_GPR(eip, "pc"), { ehframe_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, lldb_eip_i386 }, nullptr, nullptr}, - { DEFINE_GPR_BIN(eflags, "flags"), { ehframe_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, lldb_eflags_i386}, nullptr, nullptr}, -}; - -// Array of lldb register numbers used to define the set of all General Purpose Registers -uint32_t g_gpr_reg_indices[] = -{ - eRegisterIndexEax, - eRegisterIndexEbx, - eRegisterIndexEcx, - eRegisterIndexEdx, - eRegisterIndexEdi, - eRegisterIndexEsi, - eRegisterIndexEbp, - eRegisterIndexEsp, - eRegisterIndexEip, - eRegisterIndexEflags -}; - -RegisterSet g_register_sets[] = { - {"General Purpose Registers", "gpr", llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices}, -}; -} - -//------------------------------------------------------------------ -// Constructors and Destructors -//------------------------------------------------------------------ -RegisterContextWindows_x86::RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx) - : RegisterContextWindows(thread, concrete_frame_idx) -{ -} - -RegisterContextWindows_x86::~RegisterContextWindows_x86() -{ -} - -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) -{ - if (!CacheAllRegisterValues()) - return false; - - uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - switch (reg) - { - case lldb_eax_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EAX", m_context.Eax); - reg_value.SetUInt32(m_context.Eax); - break; - case lldb_ebx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EBX", m_context.Ebx); - reg_value.SetUInt32(m_context.Ebx); - break; - case lldb_ecx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ECX", m_context.Ecx); - reg_value.SetUInt32(m_context.Ecx); - break; - case lldb_edx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EDX", m_context.Edx); - reg_value.SetUInt32(m_context.Edx); - break; - case lldb_edi_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EDI", m_context.Edi); - reg_value.SetUInt32(m_context.Edi); - break; - case lldb_esi_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ESI", m_context.Esi); - reg_value.SetUInt32(m_context.Esi); - break; - case lldb_ebp_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EBP", m_context.Ebp); - reg_value.SetUInt32(m_context.Ebp); - break; - case lldb_esp_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ESP", m_context.Esp); - reg_value.SetUInt32(m_context.Esp); - break; - case lldb_eip_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EIP", m_context.Eip); - reg_value.SetUInt32(m_context.Eip); - break; - case lldb_eflags_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EFLAGS", m_context.EFlags); - reg_value.SetUInt32(m_context.EFlags); - break; - default: - WINWARN_IFALL(WINDOWS_LOG_REGISTERS, "Requested unknown register %u", reg); - 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; - - uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - switch (reg) - { - case lldb_eax_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EAX", reg_value.GetAsUInt32()); - m_context.Eax = reg_value.GetAsUInt32(); - break; - case lldb_ebx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBX", reg_value.GetAsUInt32()); - m_context.Ebx = reg_value.GetAsUInt32(); - break; - case lldb_ecx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ECX", reg_value.GetAsUInt32()); - m_context.Ecx = reg_value.GetAsUInt32(); - break; - case lldb_edx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDX", reg_value.GetAsUInt32()); - m_context.Edx = reg_value.GetAsUInt32(); - break; - case lldb_edi_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDI", reg_value.GetAsUInt32()); - m_context.Edi = reg_value.GetAsUInt32(); - break; - case lldb_esi_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESI", reg_value.GetAsUInt32()); - m_context.Esi = reg_value.GetAsUInt32(); - break; - case lldb_ebp_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBP", reg_value.GetAsUInt32()); - m_context.Ebp = reg_value.GetAsUInt32(); - break; - case lldb_esp_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESP", reg_value.GetAsUInt32()); - m_context.Esp = reg_value.GetAsUInt32(); - break; - case lldb_eip_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EIP", reg_value.GetAsUInt32()); - m_context.Eip = reg_value.GetAsUInt32(); - break; - case lldb_eflags_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EFLAGS", reg_value.GetAsUInt32()); - m_context.EFlags = reg_value.GetAsUInt32(); - break; - default: - WINWARN_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to unknown register %u", reg_value.GetAsUInt32(), - reg); - } - - // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast(m_thread); - return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); -} Index: source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h =================================================================== --- source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h +++ source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h @@ -79,9 +79,6 @@ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; - lldb::addr_t - GetImageInfoAddress() override; - lldb_private::ArchSpec GetArchitecture(); Index: source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp =================================================================== --- source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp +++ source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp @@ -285,18 +285,6 @@ }); } -lldb::addr_t -ProcessWinMiniDump::GetImageInfoAddress() -{ - Target *target = &GetTarget(); - ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(target); - - if (addr.IsValid()) - return addr.GetLoadAddress(target); - return LLDB_INVALID_ADDRESS; -} - ArchSpec ProcessWinMiniDump::GetArchitecture() { Index: source/Plugins/Process/Windows/MiniDump/RegisterContextWindowsMiniDump.h =================================================================== --- source/Plugins/Process/Windows/MiniDump/RegisterContextWindowsMiniDump.h +++ source/Plugins/Process/Windows/MiniDump/RegisterContextWindowsMiniDump.h @@ -1,73 +1,75 @@ -//===-- RegisterContextWindowsMiniDump.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_RegisterContextWindowsMiniDump_H_ -#define liblldb_RegisterContextWindowsMiniDump_H_ - -#include "lldb/lldb-forward.h" -#include "lldb/Target/RegisterContext.h" - - -namespace lldb_private -{ - -class Thread; - -class RegisterContextWindowsMiniDump : public lldb_private::RegisterContext -{ - public: - RegisterContextWindowsMiniDump(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindowsMiniDump(); - - 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; - - 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; -}; - -} - -#endif // #ifndef liblldb_RegisterContextWindowsMiniDump_H_ +//===-- RegisterContextWindowsMiniDump.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_RegisterContextWindowsMiniDump_H_ +#define liblldb_RegisterContextWindowsMiniDump_H_ + +#include "lldb/lldb-forward.h" +#include "lldb/Target/RegisterContext.h" + +#include "Plugins/Process/Windows/Common/RegisterContextWindows.h" + + +namespace lldb_private +{ + +class Thread; + +class RegisterContextWindowsMiniDump : public lldb_private::RegisterContextWindows +{ + public: + RegisterContextWindowsMiniDump(Thread &thread, uint32_t concrete_frame_idx); + + virtual ~RegisterContextWindowsMiniDump(); + + 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; + + 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; +}; + +} + +#endif // #ifndef liblldb_RegisterContextWindowsMiniDump_H_ Index: source/Plugins/Process/Windows/MiniDump/RegisterContextWindowsMiniDump.cpp =================================================================== --- source/Plugins/Process/Windows/MiniDump/RegisterContextWindowsMiniDump.cpp +++ source/Plugins/Process/Windows/MiniDump/RegisterContextWindowsMiniDump.cpp @@ -1,146 +1,146 @@ -//===-- RegisterContextWindowsMiniDump.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/lldb-private-types.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" - -#include "RegisterContextWindowsMiniDump.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -// This is a do-nothing stub implementation for now. - -RegisterContextWindowsMiniDump::RegisterContextWindowsMiniDump(Thread &thread, uint32_t concrete_frame_idx) - : RegisterContext(thread, concrete_frame_idx) -{ -} - -RegisterContextWindowsMiniDump::~RegisterContextWindowsMiniDump() -{ -} - -void -RegisterContextWindowsMiniDump::InvalidateAllRegisters() -{ -} - -size_t -RegisterContextWindowsMiniDump::GetRegisterCount() -{ - return 0; -} - -const RegisterInfo * -RegisterContextWindowsMiniDump::GetRegisterInfoAtIndex(size_t reg) -{ - return nullptr; -} - -size_t -RegisterContextWindowsMiniDump::GetRegisterSetCount() -{ - return 0; -} - -const RegisterSet * -RegisterContextWindowsMiniDump::GetRegisterSet(size_t reg_set) -{ - return nullptr; -} - -bool -RegisterContextWindowsMiniDump::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) -{ - return false; -} - -bool -RegisterContextWindowsMiniDump::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) -{ - return false; -} - -bool -RegisterContextWindowsMiniDump::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) -{ - return false; -} - -bool -RegisterContextWindowsMiniDump::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) -{ - return false; -} - -uint32_t -RegisterContextWindowsMiniDump::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; -} - -uint32_t -RegisterContextWindowsMiniDump::NumSupportedHardwareBreakpoints() -{ - // Support for hardware breakpoints not yet implemented. - return 0; -} - -uint32_t -RegisterContextWindowsMiniDump::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) -{ - return 0; -} - -bool -RegisterContextWindowsMiniDump::ClearHardwareBreakpoint(uint32_t hw_idx) -{ - return false; -} - -uint32_t -RegisterContextWindowsMiniDump::NumSupportedHardwareWatchpoints() -{ - // Support for hardware watchpoints not yet implemented. - return 0; -} - -uint32_t -RegisterContextWindowsMiniDump::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) -{ - return 0; -} - -bool -RegisterContextWindowsMiniDump::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextWindowsMiniDump::HardwareSingleStep(bool enable) -{ - return false; -} +//===-- RegisterContextWindowsMiniDump.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private-types.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/windows/HostThreadWindows.h" +#include "lldb/Host/windows/windows.h" + +#include "RegisterContextWindowsMiniDump.h" + +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; +using namespace lldb_private; + +// This is a do-nothing stub implementation for now. + +RegisterContextWindowsMiniDump::RegisterContextWindowsMiniDump(Thread &thread, uint32_t concrete_frame_idx) + : RegisterContextWindows(thread, concrete_frame_idx) +{ +} + +RegisterContextWindowsMiniDump::~RegisterContextWindowsMiniDump() +{ +} + +void +RegisterContextWindowsMiniDump::InvalidateAllRegisters() +{ +} + +size_t +RegisterContextWindowsMiniDump::GetRegisterCount() +{ + return 0; +} + +const RegisterInfo * +RegisterContextWindowsMiniDump::GetRegisterInfoAtIndex(size_t reg) +{ + return nullptr; +} + +size_t +RegisterContextWindowsMiniDump::GetRegisterSetCount() +{ + return 0; +} + +const RegisterSet * +RegisterContextWindowsMiniDump::GetRegisterSet(size_t reg_set) +{ + return nullptr; +} + +bool +RegisterContextWindowsMiniDump::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) +{ + return false; +} + +bool +RegisterContextWindowsMiniDump::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) +{ + return false; +} + +bool +RegisterContextWindowsMiniDump::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextWindowsMiniDump::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +uint32_t +RegisterContextWindowsMiniDump::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; +} + +uint32_t +RegisterContextWindowsMiniDump::NumSupportedHardwareBreakpoints() +{ + // Support for hardware breakpoints not yet implemented. + return 0; +} + +uint32_t +RegisterContextWindowsMiniDump::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) +{ + return 0; +} + +bool +RegisterContextWindowsMiniDump::ClearHardwareBreakpoint(uint32_t hw_idx) +{ + return false; +} + +uint32_t +RegisterContextWindowsMiniDump::NumSupportedHardwareWatchpoints() +{ + // Support for hardware watchpoints not yet implemented. + return 0; +} + +uint32_t +RegisterContextWindowsMiniDump::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) +{ + return 0; +} + +bool +RegisterContextWindowsMiniDump::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextWindowsMiniDump::HardwareSingleStep(bool enable) +{ + return false; +}