summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Windows/Common
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Windows/Common')
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h2
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp181
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h16
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp93
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.h26
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp4
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp4
7 files changed, 259 insertions, 67 deletions
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h
index fd0b0e5bc0a..b4d053f8834 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h
@@ -41,7 +41,7 @@ public:
HANDLE m_initial_stop_event = nullptr;
bool m_initial_stop_received = false;
bool m_stop_at_entry;
- std::map<lldb::tid_t, HostThread> m_new_threads;
+ std::map<lldb::tid_t, lldb::ThreadSP> m_new_threads;
std::set<lldb::tid_t> m_exited_threads;
};
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 7303e177b46..461dbebb3d8 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -12,6 +12,7 @@
#include "lldb/Host/windows/windows.h"
#include <psapi.h>
+#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@@ -104,7 +105,10 @@ const char *ProcessWindows::GetPluginDescriptionStatic() {
ProcessWindows::ProcessWindows(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp)
- : lldb_private::Process(target_sp, listener_sp) {}
+ : lldb_private::Process(target_sp, listener_sp),
+ m_watchpoint_ids(
+ RegisterContextWindows::GetNumHardwareBreakpointSlots(),
+ LLDB_INVALID_BREAK_ID) {}
ProcessWindows::~ProcessWindows() {}
@@ -382,11 +386,35 @@ void ProcessWindows::RefreshStateAfterStop() {
stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread,
site->GetID());
stop_thread->SetStopInfo(stop_info);
- } else {
- LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
- stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
+
+ return;
+ }
+
+ auto *reg_ctx = static_cast<RegisterContextWindows *>(
+ stop_thread->GetRegisterContext().get());
+ uint32_t slot_id = reg_ctx->GetTriggeredHardwareBreakpointSlotId();
+ if (slot_id != LLDB_INVALID_INDEX32) {
+ int id = m_watchpoint_ids[slot_id];
+ LLDB_LOG(log,
+ "Single-stepped onto a watchpoint in process {0} at address "
+ "{1:x} with watchpoint {2}",
+ m_session_data->m_debugger->GetProcess().GetProcessId(), pc, id);
+
+ if (lldb::WatchpointSP wp_sp =
+ GetTarget().GetWatchpointList().FindByID(id))
+ wp_sp->SetHardwareIndex(slot_id);
+
+ stop_info = StopInfo::CreateStopReasonWithWatchpointID(
+ *stop_thread, id, m_watchpoints[id].address);
stop_thread->SetStopInfo(stop_info);
+
+ return;
}
+
+ LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
+ stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
+ stop_thread->SetStopInfo(stop_info);
+
return;
}
@@ -494,9 +522,7 @@ bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list,
// 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_thread_list.AddThread(thread_info.second);
++new_size;
++new_threads;
LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first);
@@ -588,9 +614,9 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) {
SetProcessExitStatus(GetID(), true, 0, exit_code);
SetPrivateState(eStateExited);
- // If the process exits before any initial stop then notify the debugger
+ // If the process exits before any initial stop then notify the debugger
// of the error otherwise WaitForDebuggerConnection() will be blocked.
- // An example of this issue is when a process fails to load a dependent DLL.
+ // An example of this issue is when a process fails to load a dependent DLL.
if (m_session_data && !m_session_data->m_initial_stop_received) {
Status error(exit_code, eErrorTypeWin32);
OnDebuggerError(error, 0);
@@ -619,8 +645,8 @@ void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
FileSystem::Instance().Resolve(executable_file);
ModuleSpec module_spec(executable_file);
Status error;
- module = GetTarget().GetOrCreateModule(module_spec,
- true /* notify */, &error);
+ module =
+ GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
if (!module) {
return;
}
@@ -636,10 +662,15 @@ void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
// 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();
+
+ const HostThread &host_main_thread = debugger->GetMainThread();
+ ThreadSP main_thread =
+ std::make_shared<TargetThreadWindows>(*this, host_main_thread);
+
+ tid_t id = host_main_thread.GetNativeThread().GetThreadId();
+ main_thread->SetID(id);
+
+ m_session_data->m_new_threads[id] = main_thread;
}
ExceptionResult
@@ -711,8 +742,22 @@ ProcessWindows::OnDebugException(bool first_chance,
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;
+
+ ThreadSP thread = std::make_shared<TargetThreadWindows>(*this, new_thread);
+
+ const HostNativeThread &native_new_thread = new_thread.GetNativeThread();
+ tid_t id = native_new_thread.GetThreadId();
+ thread->SetID(id);
+
+ m_session_data->m_new_threads[id] = thread;
+
+ for (const std::map<int, WatchpointInfo>::value_type &p : m_watchpoints) {
+ auto *reg_ctx = static_cast<RegisterContextWindows *>(
+ thread->GetRegisterContext().get());
+ reg_ctx->AddHardwareBreakpoint(p.second.slot_id, p.second.address,
+ p.second.size, p.second.read,
+ p.second.write);
+ }
}
void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
@@ -770,4 +815,106 @@ void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
return;
}
}
+
+Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num) {
+ num = RegisterContextWindows::GetNumHardwareBreakpointSlots();
+ return {};
+}
+
+Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
+ num = RegisterContextWindows::GetNumHardwareBreakpointSlots();
+ after = RegisterContextWindows::DoHardwareBreakpointsTriggerAfter();
+ return {};
+}
+
+Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) {
+ Status error;
+
+ if (wp->IsEnabled()) {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+
+ WatchpointInfo info;
+ for (info.slot_id = 0;
+ info.slot_id < RegisterContextWindows::GetNumHardwareBreakpointSlots();
+ info.slot_id++)
+ if (m_watchpoint_ids[info.slot_id] == LLDB_INVALID_BREAK_ID)
+ break;
+ if (info.slot_id == RegisterContextWindows::GetNumHardwareBreakpointSlots()) {
+ error.SetErrorStringWithFormat("Can't find free slot for watchpoint %i",
+ wp->GetID());
+ return error;
+ }
+ info.address = wp->GetLoadAddress();
+ info.size = wp->GetByteSize();
+ info.read = wp->WatchpointRead();
+ info.write = wp->WatchpointWrite();
+
+ for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
+ Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
+ auto *reg_ctx = static_cast<RegisterContextWindows *>(
+ thread->GetRegisterContext().get());
+ if (!reg_ctx->AddHardwareBreakpoint(info.slot_id, info.address, info.size,
+ info.read, info.write)) {
+ error.SetErrorStringWithFormat(
+ "Can't enable watchpoint %i on thread 0x%llx", wp->GetID(),
+ thread->GetID());
+ break;
+ }
+ }
+ if (error.Fail()) {
+ for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
+ Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
+ auto *reg_ctx = static_cast<RegisterContextWindows *>(
+ thread->GetRegisterContext().get());
+ reg_ctx->RemoveHardwareBreakpoint(info.slot_id);
+ }
+ return error;
+ }
+
+ m_watchpoints[wp->GetID()] = info;
+ m_watchpoint_ids[info.slot_id] = wp->GetID();
+
+ wp->SetEnabled(true, notify);
+
+ return error;
+}
+
+Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) {
+ Status error;
+
+ if (!wp->IsEnabled()) {
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ auto it = m_watchpoints.find(wp->GetID());
+ if (it == m_watchpoints.end()) {
+ error.SetErrorStringWithFormat("Info about watchpoint %i is not found",
+ wp->GetID());
+ return error;
+ }
+
+ for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
+ Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
+ auto *reg_ctx = static_cast<RegisterContextWindows *>(
+ thread->GetRegisterContext().get());
+ if (!reg_ctx->RemoveHardwareBreakpoint(it->second.slot_id)) {
+ error.SetErrorStringWithFormat(
+ "Can't disable watchpoint %i on thread 0x%llx", wp->GetID(),
+ thread->GetID());
+ break;
+ }
+ }
+ if (error.Fail())
+ return error;
+
+ m_watchpoint_ids[it->second.slot_id] = LLDB_INVALID_BREAK_ID;
+ m_watchpoints.erase(it);
+
+ wp->SetEnabled(false, notify);
+
+ return error;
+}
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
index 8d5134a49a4..a1085df022c 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
@@ -98,6 +98,22 @@ public:
void OnUnloadDll(lldb::addr_t module_addr) override;
void OnDebugString(const std::string &string) override;
void OnDebuggerError(const Status &error, uint32_t type) override;
+
+ Status GetWatchpointSupportInfo(uint32_t &num) override;
+ Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
+ Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override;
+ Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
+
+private:
+ struct WatchpointInfo {
+ uint32_t slot_id;
+ lldb::addr_t address;
+ uint32_t size;
+ bool read;
+ bool write;
+ };
+ std::map<lldb::break_id_t, WatchpointInfo> m_watchpoints;
+ std::vector<lldb::break_id_t> m_watchpoint_ids;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp
index b4a442c77ed..597673b8522 100644
--- a/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp
@@ -17,6 +17,7 @@
#include "TargetThreadWindows.h"
#include "llvm/ADT/STLExtras.h"
+#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
@@ -52,13 +53,7 @@ bool RegisterContextWindows::WriteAllRegisterValues(
assert(data_sp->GetByteSize() >= sizeof(m_context));
memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context));
- TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
- if (!::SetThreadContext(
- wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
- &m_context))
- return false;
-
- return true;
+ return ApplyAllRegisterValues();
}
uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber(
@@ -76,37 +71,69 @@ uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber(
return LLDB_INVALID_REGNUM;
}
-// Subclasses can these functions if desired
-uint32_t RegisterContextWindows::NumSupportedHardwareBreakpoints() {
- // Support for hardware breakpoints not yet implemented.
- return 0;
-}
+bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; }
-uint32_t RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr,
- size_t size) {
- return 0;
-}
+bool RegisterContextWindows::AddHardwareBreakpoint(uint32_t slot,
+ lldb::addr_t address,
+ uint32_t size, bool read,
+ bool write) {
+ if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS)
+ return false;
-bool RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) {
- return false;
-}
+ switch (size) {
+ case 1:
+ case 2:
+ case 4:
+#if defined(_M_AMD64)
+ case 8:
+#endif
+ break;
+ default:
+ return false;
+ }
-uint32_t RegisterContextWindows::NumSupportedHardwareWatchpoints() {
- // Support for hardware watchpoints not yet implemented.
- return 0;
-}
+ if (!CacheAllRegisterValues())
+ return false;
+
+ unsigned shift = 2 * slot;
+ m_context.Dr7 |= 1ULL << shift;
+
+ (&m_context.Dr0)[slot] = address;
-uint32_t RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr,
- size_t size, bool read,
- bool write) {
- return 0;
+ shift = 18 + 4 * slot;
+ m_context.Dr7 &= ~(3ULL << shift);
+ m_context.Dr7 |= (size == 8 ? 2ULL : size - 1) << shift;
+
+ shift = 16 + 4 * slot;
+ m_context.Dr7 &= ~(3ULL << shift);
+ m_context.Dr7 |= (read ? 3ULL : (write ? 1ULL : 0)) << shift;
+
+ return ApplyAllRegisterValues();
}
-bool RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) {
- return false;
+bool RegisterContextWindows::RemoveHardwareBreakpoint(uint32_t slot) {
+ if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS)
+ return false;
+
+ if (!CacheAllRegisterValues())
+ return false;
+
+ unsigned shift = 2 * slot;
+ m_context.Dr7 &= ~(1ULL << shift);
+
+ return ApplyAllRegisterValues();
}
-bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; }
+uint32_t RegisterContextWindows::GetTriggeredHardwareBreakpointSlotId() {
+ if (!CacheAllRegisterValues())
+ return LLDB_INVALID_INDEX32;
+
+ for (unsigned i = 0UL; i < NUM_HARDWARE_BREAKPOINT_SLOTS; i++)
+ if (m_context.Dr6 & (1ULL << i))
+ return i;
+
+ return LLDB_INVALID_INDEX32;
+}
bool RegisterContextWindows::CacheAllRegisterValues() {
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS);
@@ -146,3 +173,9 @@ bool RegisterContextWindows::CacheAllRegisterValues() {
m_context_stale = false;
return true;
}
+
+bool RegisterContextWindows::ApplyAllRegisterValues() {
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ return ::SetThreadContext(
+ wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context);
+}
diff --git a/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.h b/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.h
index 916f9f3a156..9ae04022825 100644
--- a/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/RegisterContextWindows.h
@@ -33,28 +33,28 @@ public:
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;
+ bool HardwareSingleStep(bool enable) override;
- uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
- bool write) override;
+ static constexpr uint32_t GetNumHardwareBreakpointSlots() {
+ return NUM_HARDWARE_BREAKPOINT_SLOTS;
+ }
+ static constexpr bool DoHardwareBreakpointsTriggerAfter() { return true; }
- bool ClearHardwareWatchpoint(uint32_t hw_index) override;
+ bool AddHardwareBreakpoint(uint32_t slot, lldb::addr_t address, uint32_t size,
+ bool read, bool write);
+ bool RemoveHardwareBreakpoint(uint32_t slot);
- bool HardwareSingleStep(bool enable) override;
+ uint32_t GetTriggeredHardwareBreakpointSlotId();
protected:
+ static constexpr unsigned NUM_HARDWARE_BREAKPOINT_SLOTS = 4;
+
virtual bool CacheAllRegisterValues();
+ virtual bool ApplyAllRegisterValues();
CONTEXT m_context;
bool m_context_stale;
};
-}
+} // namespace lldb_private
#endif // #ifndef liblldb_RegisterContextWindows_H_
diff --git a/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp b/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
index 014b15c925b..fc59d099d2d 100644
--- a/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
@@ -532,9 +532,7 @@ bool RegisterContextWindows_x64::WriteRegister(const RegisterInfo *reg_info,
}
// Physically update the registers in the target process.
- TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
- return ::SetThreadContext(
- wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context);
+ return ApplyAllRegisterValues();
}
#endif // defined(__x86_64__) || defined(_M_X64)
diff --git a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
index b8f7bb46181..2a271ac44e4 100644
--- a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
@@ -267,9 +267,7 @@ bool RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info,
}
// Physically update the registers in the target process.
- TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
- return ::SetThreadContext(
- wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context);
+ return ApplyAllRegisterValues();
}
bool RegisterContextWindows_x86::ReadRegisterHelper(
OpenPOWER on IntegriCloud