aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/nat/windows-nat.h7
-rw-r--r--gdb/windows-nat.c108
-rw-r--r--gdbserver/win32-low.cc8
-rw-r--r--gdbserver/win32-low.h2
4 files changed, 98 insertions, 27 deletions
diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h
index 6283ff0..2efb54e 100644
--- a/gdb/nat/windows-nat.h
+++ b/gdb/nat/windows-nat.h
@@ -205,6 +205,13 @@ struct windows_process_info
virtual bool handle_access_violation (const EXCEPTION_RECORD *rec) = 0;
+ /* Fill in the thread's CONTEXT/WOW64_CONTEXT, if it wasn't filled
+ in yet.
+
+ This function must be supplied by the embedding application. */
+
+ virtual void fill_thread_context (windows_thread_info *th) = 0;
+
handle_exception_result handle_exception
(DEBUG_EVENT &current_event,
struct target_waitstatus *ourstatus, bool debug_exceptions);
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index bdabe67..e11cc95 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -114,6 +114,7 @@ struct windows_per_inferior : public windows_process_info
bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
void invalidate_context (windows_thread_info *th);
+ void fill_thread_context (windows_thread_info *th) override;
void continue_one_thread (windows_thread_info *th,
windows_continue_flags cont_flags);
@@ -747,17 +748,10 @@ windows_fetch_one_register (struct regcache *regcache,
}
void
-windows_nat_target::fetch_registers (struct regcache *regcache, int r)
+windows_per_inferior::fill_thread_context (windows_thread_info *th)
{
- windows_thread_info *th = windows_process.find_thread (regcache->ptid ());
-
- /* Check if TH exists. Windows sometimes uses a non-existent
- thread id in its events. */
- if (th == NULL)
- return;
-
#ifdef __x86_64__
- if (windows_process.wow64_process)
+ if (wow64_process)
{
if (th->wow64_context.ContextFlags == 0)
{
@@ -774,6 +768,19 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
CHECK (GetThreadContext (th->h, &th->context));
}
}
+}
+
+void
+windows_nat_target::fetch_registers (struct regcache *regcache, int r)
+{
+ windows_thread_info *th = windows_process.find_thread (regcache->ptid ());
+
+ /* Check if TH exists. Windows sometimes uses a non-existent
+ thread id in its events. */
+ if (th == nullptr)
+ return;
+
+ windows_process.fill_thread_context (th);
if (r < 0)
for (r = 0; r < gdbarch_num_regs (regcache->arch()); r++)
@@ -1292,36 +1299,83 @@ windows_per_inferior::continue_one_thread (windows_thread_info *th,
DWORD &context_flags_ref = (wow64_process
? th->wow64_context.ContextFlags
: th->context.ContextFlags);
+ const DWORD64 dr6 = (wow64_process
+ ? th->wow64_context.Dr6
+ : th->context.Dr6);
#else
DWORD &context_flags_ref = th->context.ContextFlags;
+ const DWORD dr6 = th->context.Dr6;
#endif
if (th->debug_registers_changed)
{
- context_flags_ref |= CONTEXT_DEBUG_REGISTERS;
-#ifdef __x86_64__
- if (wow64_process)
+ windows_process.fill_thread_context (th);
+
+ gdb_assert ((context_flags_ref & CONTEXT_DEBUG_REGISTERS) != 0);
+
+ /* Check whether the thread has Dr6 set indicating a
+ watchpoint hit, and we haven't seen the watchpoint event
+ yet (reported as
+ EXCEPTION_SINGLE_STEP/STATUS_WX86_SINGLE_STEP). In that
+ case, don't change the debug registers. Changing debug
+ registers, even if to the same values, makes the kernel
+ clear Dr6. The result would be we would lose the
+ unreported watchpoint hit. */
+ if ((dr6 & ~DR6_CLEAR_VALUE) != 0)
{
- th->wow64_context.Dr0 = state->dr_mirror[0];
- th->wow64_context.Dr1 = state->dr_mirror[1];
- th->wow64_context.Dr2 = state->dr_mirror[2];
- th->wow64_context.Dr3 = state->dr_mirror[3];
- th->wow64_context.Dr6 = DR6_CLEAR_VALUE;
- th->wow64_context.Dr7 = state->dr_control_mirror;
+ if (th->last_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+ && (th->last_event.u.Exception.ExceptionRecord.ExceptionCode
+ == EXCEPTION_SINGLE_STEP
+ || (th->last_event.u.Exception.ExceptionRecord.ExceptionCode
+ == STATUS_WX86_SINGLE_STEP)))
+ {
+ DEBUG_EVENTS ("0x%x already reported watchpoint", th->tid);
+ }
+ else
+ {
+ DEBUG_EVENTS ("0x%x last reported something else (0x%x)",
+ th->tid,
+ th->last_event.dwDebugEventCode);
+
+ /* Don't touch debug registers. Let the pending
+ watchpoint event be reported instead. We will
+ update the debug registers later when the thread
+ is re-resumed by the core after the watchpoint
+ event. */
+ context_flags_ref &= ~CONTEXT_DEBUG_REGISTERS;
+ }
}
else
-#endif
+ DEBUG_EVENTS ("0x%x has no dr6 set", th->tid);
+
+ if ((context_flags_ref & CONTEXT_DEBUG_REGISTERS) != 0)
{
- th->context.Dr0 = state->dr_mirror[0];
- th->context.Dr1 = state->dr_mirror[1];
- th->context.Dr2 = state->dr_mirror[2];
- th->context.Dr3 = state->dr_mirror[3];
- th->context.Dr6 = DR6_CLEAR_VALUE;
- th->context.Dr7 = state->dr_control_mirror;
- }
+ DEBUG_EVENTS ("0x%x changing dregs", th->tid);
+#ifdef __x86_64__
+ if (wow64_process)
+ {
+ th->wow64_context.Dr0 = state->dr_mirror[0];
+ th->wow64_context.Dr1 = state->dr_mirror[1];
+ th->wow64_context.Dr2 = state->dr_mirror[2];
+ th->wow64_context.Dr3 = state->dr_mirror[3];
+ th->wow64_context.Dr6 = DR6_CLEAR_VALUE;
+ th->wow64_context.Dr7 = state->dr_control_mirror;
+ }
+ else
+#endif
+ {
+ th->context.Dr0 = state->dr_mirror[0];
+ th->context.Dr1 = state->dr_mirror[1];
+ th->context.Dr2 = state->dr_mirror[2];
+ th->context.Dr3 = state->dr_mirror[3];
+ th->context.Dr6 = DR6_CLEAR_VALUE;
+ th->context.Dr7 = state->dr_control_mirror;
+ }
- th->debug_registers_changed = false;
+ th->debug_registers_changed = false;
+ }
}
+
if (context_flags_ref != 0)
{
DWORD ec = 0;
diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc
index 004bf94..65b01dc 100644
--- a/gdbserver/win32-low.cc
+++ b/gdbserver/win32-low.cc
@@ -141,6 +141,14 @@ win32_require_context (windows_thread_info *th)
/* See nat/windows-nat.h. */
+void
+gdbserver_windows_process::fill_thread_context (windows_thread_info *th)
+{
+ win32_require_context (th);
+}
+
+/* See nat/windows-nat.h. */
+
windows_thread_info *
gdbserver_windows_process::find_thread (ptid_t ptid)
{
diff --git a/gdbserver/win32-low.h b/gdbserver/win32-low.h
index e99e47e..ea2a9b4 100644
--- a/gdbserver/win32-low.h
+++ b/gdbserver/win32-low.h
@@ -181,6 +181,8 @@ struct gdbserver_windows_process : public windows_nat::windows_process_info
void handle_unload_dll (const DEBUG_EVENT &current_event) override;
bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
+ void fill_thread_context (windows_nat::windows_thread_info *th) override;
+
int attaching = 0;
/* A status that hasn't been reported to the core yet, and so