summaryrefslogtreecommitdiff
path: root/gdb/gdbserver/win32-low.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-10-15 19:55:50 +0100
committerPedro Alves <palves@redhat.com>2014-10-15 19:55:50 +0100
commita2abc7de6804e7e9882a86375767b24a6c215f28 (patch)
tree13180db176ef84f0ca1ce7aa55365a0f989fb05f /gdb/gdbserver/win32-low.c
parent6979730b1b9378a143b1bea3d0ff7b96c7bf02c5 (diff)
downloadbinutils-gdb-a2abc7de6804e7e9882a86375767b24a6c215f28.tar.gz
gdbserver/win32: Rewrite debug registers handling
Don't use debug_reg_state for both: * "intent" - what we want the debug registers to look like * "reality" - what/which were the contents of the DR registers when the event triggered Reserve it for the former only, like in the GNU/Linux port. Otherwise the core x86 debug registers code can get confused if the inferior itself changes the debug registers since GDB last set them. This is also a requirement for being able to set watchpoints while the target is running, if/when we get to it on Windows. See the big comment in x86_dr_stopped_data_address. Seems to me this may also fixes propagating watchpoints to all threads -- continue_one_thread only calls win32_set_thread_context (what copies the DR registers to the thread), if something already fetched the thread's context before. Something else may be masking this issue, I haven't checked. Smoke tested by running gdbserver under Wine, connecting to it from GNU/Linux, and checking that I could trigger a watchpoint as expected. Joel tested it on x86-windows using AdaCore's testsuite. gdb/gdbserver/ 2014-10-15 Pedro Alves <palves@redhat.com> PR server/17487 * win32-arm-low.c (arm_set_thread_context): Remove current_event parameter. (arm_set_thread_context): Delete. (the_low_target): Adjust. * win32-i386-low.c (debug_registers_changed) (debug_registers_used): Delete. (update_debug_registers_callback): New function. (x86_dr_low_set_addr, x86_dr_low_set_control): Mark all threads as needing to update their debug registers. (win32_get_current_dr): New function. (x86_dr_low_get_addr, x86_dr_low_get_control) (x86_dr_low_get_status): Fetch the debug register from the thread record's context. (i386_initial_stuff): Adjust. (i386_get_thread_context): Remove current_event parameter. Don't clear debug_registers_changed nor copy DR values to debug_reg_state. (i386_set_thread_context): Delete. (i386_prepare_to_resume): New function. (i386_thread_added): Mark the thread as needing to update irs debug registers. (the_low_target): Remove i386_set_thread_context and install i386_prepare_to_resume. * win32-low.c (win32_get_thread_context): Adjust. (win32_set_thread_context): Use SetThreadContext directly. (win32_prepare_to_resume): New function. (win32_require_context): New function, factored out from ... (thread_rec): ... this. (continue_one_thread): Call win32_prepare_to_resume on each thread we're about to continue. (win32_resume): Call win32_prepare_to_resume on the event thread. * win32-low.h (struct win32_thread_info) <debug_registers_changed>: New field. (struct win32_target_ops): Change prototype of set_thread_context, delete set_thread_context and add prepare_to_resume. (win32_require_context): New declaration.
Diffstat (limited to 'gdb/gdbserver/win32-low.c')
-rw-r--r--gdb/gdbserver/win32-low.c73
1 files changed, 48 insertions, 25 deletions
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index ee99fe4126a..e714933eb01 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -129,7 +129,7 @@ static void
win32_get_thread_context (win32_thread_info *th)
{
memset (&th->context, 0, sizeof (CONTEXT));
- (*the_low_target.get_thread_context) (th, &current_event);
+ (*the_low_target.get_thread_context) (th);
#ifdef _WIN32_WCE
memcpy (&th->base_context, &th->context, sizeof (CONTEXT));
#endif
@@ -153,23 +153,24 @@ win32_set_thread_context (win32_thread_info *th)
it between stopping and resuming. */
if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0)
#endif
- (*the_low_target.set_thread_context) (th, &current_event);
+ SetThreadContext (th->h, &th->context);
}
-/* Find a thread record given a thread id. If GET_CONTEXT is set then
- also retrieve the context for this thread. */
-static win32_thread_info *
-thread_rec (ptid_t ptid, int get_context)
+/* Set the thread context of the thread associated with TH. */
+
+static void
+win32_prepare_to_resume (win32_thread_info *th)
{
- struct thread_info *thread;
- win32_thread_info *th;
+ if (the_low_target.prepare_to_resume != NULL)
+ (*the_low_target.prepare_to_resume) (th);
+}
- thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
- if (thread == NULL)
- return NULL;
+/* See win32-low.h. */
- th = inferior_target_data (thread);
- if (get_context && th->context.ContextFlags == 0)
+void
+win32_require_context (win32_thread_info *th)
+{
+ if (th->context.ContextFlags == 0)
{
if (!th->suspended)
{
@@ -185,7 +186,23 @@ thread_rec (ptid_t ptid, int get_context)
win32_get_thread_context (th);
}
+}
+/* Find a thread record given a thread id. If GET_CONTEXT is set then
+ also retrieve the context for this thread. */
+static win32_thread_info *
+thread_rec (ptid_t ptid, int get_context)
+{
+ struct thread_info *thread;
+ win32_thread_info *th;
+
+ thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
+ if (thread == NULL)
+ return NULL;
+
+ th = inferior_target_data (thread);
+ if (get_context)
+ win32_require_context (th);
return th;
}
@@ -419,22 +436,26 @@ continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr)
int thread_id = * (int *) id_ptr;
win32_thread_info *th = inferior_target_data (thread);
- if ((thread_id == -1 || thread_id == th->tid)
- && th->suspended)
+ if (thread_id == -1 || thread_id == th->tid)
{
- if (th->context.ContextFlags)
- {
- win32_set_thread_context (th);
- th->context.ContextFlags = 0;
- }
+ win32_prepare_to_resume (th);
- if (ResumeThread (th->h) == (DWORD) -1)
+ if (th->suspended)
{
- DWORD err = GetLastError ();
- OUTMSG (("warning: ResumeThread failed in continue_one_thread, "
- "(error %d): %s\n", (int) err, strwinerror (err)));
+ if (th->context.ContextFlags)
+ {
+ win32_set_thread_context (th);
+ th->context.ContextFlags = 0;
+ }
+
+ if (ResumeThread (th->h) == (DWORD) -1)
+ {
+ DWORD err = GetLastError ();
+ OUTMSG (("warning: ResumeThread failed in continue_one_thread, "
+ "(error %d): %s\n", (int) err, strwinerror (err)));
+ }
+ th->suspended = 0;
}
- th->suspended = 0;
}
return 0;
@@ -937,6 +958,8 @@ win32_resume (struct thread_resume *resume_info, size_t n)
th = thread_rec (ptid, FALSE);
if (th)
{
+ win32_prepare_to_resume (th);
+
if (th->context.ContextFlags)
{
/* Move register values from the inferior into the thread