[21/34] Windows gdb+gdbserver: Make current_event per-thread state

Message ID 20240507234233.371123-22-pedro@palves.net
State New
Headers
Series Windows non-stop mode |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Testing passed

Commit Message

Pedro Alves May 7, 2024, 11:42 p.m. UTC
  With non-stop mode, each thread is controlled independently of the
others, and each thread has its own independent reason for its last
stop.

Thus, any thread-specific state that is currently per-process must be
converted to per-thread state.

This patch converts windows_process_info::current_event, moving it to
windows_thread_info instead, renamed to last_event.

Since each thread will have its own copy of its last Windows debug
event, we no longer need the same information stored in struct
pending_stop.

Since windows_process.current_event no longer exists, we need to pass
the current event as parameter to a number of methods.

This adjusts both native gdb and gdbserver.

Change-Id: Ice09a5d932c912210608d5af25e1898f823e3c99
---
 gdb/nat/windows-nat.c  |  13 ++--
 gdb/nat/windows-nat.h  |  24 ++++----
 gdb/windows-nat.c      | 136 ++++++++++++++++++++++-------------------
 gdbserver/win32-low.cc |  70 ++++++++++-----------
 gdbserver/win32-low.h  |   5 +-
 5 files changed, 129 insertions(+), 119 deletions(-)
  

Patch

diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c
index 7f8834facd4..cabc61fb2d2 100644
--- a/gdb/nat/windows-nat.c
+++ b/gdb/nat/windows-nat.c
@@ -310,8 +310,10 @@  get_image_name (HANDLE h, void *address, int unicode)
 /* See nat/windows-nat.h.  */
 
 bool
-windows_process_info::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
+windows_process_info::handle_ms_vc_exception (const DEBUG_EVENT &current_event)
 {
+  const EXCEPTION_RECORD *rec = &current_event.u.Exception.ExceptionRecord;
+
   if (rec->NumberParameters >= 3
       && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000)
     {
@@ -352,7 +354,8 @@  windows_process_info::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
 #define MS_VC_EXCEPTION 0x406d1388
 
 handle_exception_result
-windows_process_info::handle_exception (struct target_waitstatus *ourstatus,
+windows_process_info::handle_exception (DEBUG_EVENT &current_event,
+					struct target_waitstatus *ourstatus,
 					bool debug_exceptions)
 {
 #define DEBUG_EXCEPTION_SIMPLE(x)       if (debug_exceptions) \
@@ -480,7 +483,7 @@  windows_process_info::handle_exception (struct target_waitstatus *ourstatus,
       break;
     case MS_VC_EXCEPTION:
       DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
-      if (handle_ms_vc_exception (rec))
+      if (handle_ms_vc_exception (current_event))
 	{
 	  ourstatus->set_stopped (GDB_SIGNAL_TRAP);
 	  result = HANDLE_EXCEPTION_IGNORED;
@@ -634,11 +637,11 @@  windows_process_info::add_dll (LPVOID load_addr)
 /* See nat/windows-nat.h.  */
 
 void
-windows_process_info::dll_loaded_event ()
+windows_process_info::dll_loaded_event (const DEBUG_EVENT &current_event)
 {
   gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT);
 
-  LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
+  const LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
   const char *dll_name;
 
   /* Try getting the DLL name via the lpImageName field of the event.
diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h
index 70912fd6210..73c828ec2c9 100644
--- a/gdb/nat/windows-nat.h
+++ b/gdb/nat/windows-nat.h
@@ -40,10 +40,6 @@  struct pending_stop
   /* The target waitstatus we computed.  TARGET_WAITKIND_IGNORE if the
      thread does not have a pending stop.  */
   target_waitstatus status;
-
-  /* The event.  A few fields of this can be referenced after a stop,
-     and it seemed simplest to store the entire event.  */
-  DEBUG_EVENT event;
 };
 
 
@@ -98,6 +94,10 @@  struct windows_thread_info
    process them once the step has completed.  See PR gdb/22992.  */
   struct pending_stop pending_stop {};
 
+  /* The last Windows event returned by WaitForDebugEvent for this
+     thread.  */
+  DEBUG_EVENT last_event {};
+
   /* The context of the thread, including any manipulations.  */
   union
   {
@@ -143,10 +143,6 @@  struct windows_process_info
   DWORD main_thread_id = 0;
   enum gdb_signal last_sig = GDB_SIGNAL_0;
 
-  /* The current debug event from WaitForDebugEvent or from a pending
-     stop.  */
-  DEBUG_EVENT current_event {};
-
   /* Contents of $_siginfo */
   EXCEPTION_RECORD siginfo_er {};
 
@@ -170,7 +166,8 @@  struct windows_process_info
      a Cygwin signal.  Otherwise just print the string as a warning.
 
      This function must be supplied by the embedding application.  */
-  virtual DWORD handle_output_debug_string (struct target_waitstatus *ourstatus) = 0;
+  virtual DWORD handle_output_debug_string (const DEBUG_EVENT &current_event,
+					    struct target_waitstatus *ourstatus) = 0;
 
   /* Handle a DLL load event.
 
@@ -191,7 +188,7 @@  struct windows_process_info
 
      This function must be supplied by the embedding application.  */
 
-  virtual void handle_unload_dll () = 0;
+  virtual void handle_unload_dll (const DEBUG_EVENT &current_event) = 0;
 
   /* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding
      application a chance to change it to be considered "unhandled".
@@ -201,11 +198,12 @@  struct windows_process_info
   virtual bool handle_access_violation (const EXCEPTION_RECORD *rec) = 0;
 
   handle_exception_result handle_exception
-       (struct target_waitstatus *ourstatus, bool debug_exceptions);
+      (DEBUG_EVENT &current_event,
+       struct target_waitstatus *ourstatus, bool debug_exceptions);
 
   /* Call to indicate that a DLL was loaded.  */
 
-  void dll_loaded_event ();
+  void dll_loaded_event (const DEBUG_EVENT &current_event);
 
   /* Iterate over all DLLs currently mapped by our inferior, and
      add them to our list of solibs.  */
@@ -222,7 +220,7 @@  struct windows_process_info
 
      Return true if the exception was handled; return false otherwise.  */
 
-  bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec);
+  bool handle_ms_vc_exception (const DEBUG_EVENT &current_event);
 
   /* Iterate over all DLLs currently mapped by our inferior, looking for
      a DLL which is loaded at LOAD_ADDR.  If found, add the DLL to our
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 5ebf53e2816..1a01ae57e54 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -107,9 +107,10 @@  DEF_ENUM_FLAGS_TYPE (windows_continue_flag, windows_continue_flags);
 struct windows_per_inferior : public windows_process_info
 {
   windows_thread_info *find_thread (ptid_t ptid) override;
-  DWORD handle_output_debug_string (struct target_waitstatus *ourstatus) override;
+  DWORD handle_output_debug_string (const DEBUG_EVENT &current_event,
+				    struct target_waitstatus *ourstatus) override;
   void handle_load_dll (const char *dll_name, LPVOID base) override;
-  void handle_unload_dll () override;
+  void handle_unload_dll (const DEBUG_EVENT &current_event) override;
   bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
 
   void invalidate_context (windows_thread_info *th);
@@ -321,7 +322,8 @@  struct windows_nat_target final : public x86_nat_target<inf_child_target>
   const char *thread_name (struct thread_info *) override;
 
   ptid_t get_windows_debug_event (int pid, struct target_waitstatus *ourstatus,
-				  target_wait_flags options);
+				  target_wait_flags options,
+				  DEBUG_EVENT *current_event);
 
   void do_initial_windows_stuff (DWORD pid, bool attaching);
 
@@ -352,7 +354,7 @@  struct windows_nat_target final : public x86_nat_target<inf_child_target>
   windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
 				   bool main_thread_p);
   void delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p);
-  DWORD fake_create_process ();
+  DWORD fake_create_process (const DEBUG_EVENT &current_event);
 
   BOOL windows_continue (DWORD continue_status, int id,
 			 windows_continue_flags cont_flags = 0);
@@ -979,7 +981,7 @@  windows_per_inferior::handle_load_dll (const char *dll_name, LPVOID base)
 /* See nat/windows-nat.h.  */
 
 void
-windows_per_inferior::handle_unload_dll ()
+windows_per_inferior::handle_unload_dll (const DEBUG_EVENT &current_event)
 {
   LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll;
 
@@ -1042,7 +1044,8 @@  signal_event_command (const char *args, int from_tty)
 
 DWORD
 windows_per_inferior::handle_output_debug_string
-     (struct target_waitstatus *ourstatus)
+  (const DEBUG_EVENT &current_event,
+   struct target_waitstatus *ourstatus)
 {
   DWORD thread_id = 0;
 
@@ -1387,11 +1390,11 @@  windows_nat_target::windows_continue (DWORD continue_status, int id,
 /* Called in pathological case where Windows fails to send a
    CREATE_PROCESS_DEBUG_EVENT after an attach.  */
 DWORD
-windows_nat_target::fake_create_process ()
+windows_nat_target::fake_create_process (const DEBUG_EVENT &current_event)
 {
   windows_process.handle
     = OpenProcess (PROCESS_ALL_ACCESS, FALSE,
-		   windows_process.current_event.dwProcessId);
+		   current_event.dwProcessId);
   if (windows_process.handle != NULL)
     windows_process.open_process_used = 1;
   else
@@ -1400,12 +1403,11 @@  windows_nat_target::fake_create_process ()
       throw_winerror_with_name (_("OpenProcess call failed"), err);
       /*  We can not debug anything in that case.  */
     }
-  add_thread (ptid_t (windows_process.current_event.dwProcessId,
-		      windows_process.current_event.dwThreadId, 0),
-		      windows_process.current_event.u.CreateThread.hThread,
-		      windows_process.current_event.u.CreateThread.lpThreadLocalBase,
+  add_thread (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
+		      current_event.u.CreateThread.hThread,
+		      current_event.u.CreateThread.lpThreadLocalBase,
 		      true /* main_thread_p */);
-  return windows_process.current_event.dwThreadId;
+  return current_event.dwThreadId;
 }
 
 void
@@ -1422,6 +1424,13 @@  windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
   if (resume_all)
     ptid = inferior_ptid;
 
+  DEBUG_EXEC ("pid=%d, tid=0x%x, step=%d, sig=%d",
+	      ptid.pid (), (unsigned) ptid.lwp (), step, sig);
+
+  /* Get currently selected thread.  */
+  th = windows_process.find_thread (inferior_ptid);
+  gdb_assert (th != nullptr);
+
   if (sig != GDB_SIGNAL_0)
     {
       /* Note it is OK to call get_last_debug_event_ptid() from the
@@ -1434,8 +1443,7 @@  windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
 	  DEBUG_EXCEPT ("Cannot continue with signal %d here.  "
 			"Not last-event thread", sig);
 	}
-      else if (windows_process.current_event.dwDebugEventCode
-	  != EXCEPTION_DEBUG_EVENT)
+      else if (th->last_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
 	{
 	  DEBUG_EXCEPT ("Cannot continue with signal %d here.  "
 			"Not stopped for EXCEPTION_DEBUG_EVENT", sig);
@@ -1452,7 +1460,7 @@  windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
 	  for (const xlate_exception &x : xlate)
 	    if (x.us == sig)
 	      {
-		current_event.u.Exception.ExceptionRecord.ExceptionCode
+		th->last_event.u.Exception.ExceptionRecord.ExceptionCode
 		  = x.them;
 		continue_status = DBG_EXCEPTION_NOT_HANDLED;
 		break;
@@ -1469,36 +1477,28 @@  windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
 
   windows_process.last_sig = GDB_SIGNAL_0;
 
-  DEBUG_EXEC ("pid=%d, tid=0x%x, step=%d, sig=%d",
-	      ptid.pid (), (unsigned) ptid.lwp (), step, sig);
-
-  /* Get context for currently selected thread.  */
-  th = windows_process.find_thread (inferior_ptid);
-  if (th)
-    {
 #ifdef __x86_64__
-      if (windows_process.wow64_process)
+  if (windows_process.wow64_process)
+    {
+      if (step)
 	{
-	  if (step)
-	    {
-	      /* Single step by setting t bit.  */
-	      regcache *regcache = get_thread_regcache (inferior_thread ());
-	      struct gdbarch *gdbarch = regcache->arch ();
-	      fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
-	      th->wow64_context.EFlags |= FLAG_TRACE_BIT;
-	    }
+	  /* Single step by setting t bit.  */
+	  regcache *regcache = get_thread_regcache (inferior_thread ());
+	  struct gdbarch *gdbarch = regcache->arch ();
+	  fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
+	  th->wow64_context.EFlags |= FLAG_TRACE_BIT;
 	}
-      else
+    }
+  else
 #endif
+    {
+      if (step)
 	{
-	  if (step)
-	    {
-	      /* Single step by setting t bit.  */
-	      regcache *regcache = get_thread_regcache (inferior_thread ());
-	      struct gdbarch *gdbarch = regcache->arch ();
-	      fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
-	      th->context.EFlags |= FLAG_TRACE_BIT;
-	    }
+	  /* Single step by setting t bit.  */
+	  regcache *regcache = get_thread_regcache (inferior_thread ());
+	  struct gdbarch *gdbarch = regcache->arch ();
+	  fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
+	  th->context.EFlags |= FLAG_TRACE_BIT;
 	}
     }
 
@@ -1562,7 +1562,8 @@  windows_nat_target::pass_ctrlc ()
 
 ptid_t
 windows_nat_target::get_windows_debug_event
-     (int pid, struct target_waitstatus *ourstatus, target_wait_flags options)
+  (int pid, struct target_waitstatus *ourstatus, target_wait_flags options,
+   DEBUG_EVENT *current_event)
 {
   DWORD continue_status, event_code;
   DWORD thread_id = 0;
@@ -1580,7 +1581,7 @@  windows_nat_target::get_windows_debug_event
 	  thread_id = th->tid;
 	  *ourstatus = th->pending_stop.status;
 	  th->pending_stop.status.set_ignore ();
-	  windows_process.current_event = th->pending_stop.event;
+	  *current_event = th->last_event;
 
 	  ptid_t ptid (windows_process.process_id, thread_id);
 	  windows_process.invalidate_context (th.get ());
@@ -1589,7 +1590,6 @@  windows_nat_target::get_windows_debug_event
     }
 
   windows_process.last_sig = GDB_SIGNAL_0;
-  DEBUG_EVENT *current_event = &windows_process.current_event;
 
   if ((options & TARGET_WNOHANG) != 0 && !m_debug_event_pending)
     {
@@ -1597,11 +1597,11 @@  windows_nat_target::get_windows_debug_event
       return minus_one_ptid;
     }
 
-  wait_for_debug_event_main_thread (&windows_process.current_event);
+  wait_for_debug_event_main_thread (current_event);
 
   continue_status = DBG_CONTINUE;
 
-  event_code = windows_process.current_event.dwDebugEventCode;
+  event_code = current_event->dwDebugEventCode;
   ourstatus->set_spurious ();
 
   switch (event_code)
@@ -1619,7 +1619,7 @@  windows_nat_target::get_windows_debug_event
 	      /* Kludge around a Windows bug where first event is a create
 		 thread event.  Caused when attached process does not have
 		 a main thread.  */
-	      thread_id = fake_create_process ();
+	      thread_id = fake_create_process (*current_event);
 	      if (thread_id)
 		windows_process.saw_create++;
 	    }
@@ -1716,7 +1716,7 @@  windows_nat_target::get_windows_debug_event
 	break;
       try
 	{
-	  windows_process.dll_loaded_event ();
+	  windows_process.dll_loaded_event (*current_event);
 	}
       catch (const gdb_exception &ex)
 	{
@@ -1736,7 +1736,7 @@  windows_nat_target::get_windows_debug_event
 	break;
       try
 	{
-	  windows_process.handle_unload_dll ();
+	  windows_process.handle_unload_dll (*current_event);
 	}
       catch (const gdb_exception &ex)
 	{
@@ -1753,7 +1753,8 @@  windows_nat_target::get_windows_debug_event
 		    "EXCEPTION_DEBUG_EVENT");
       if (windows_process.saw_create != 1)
 	break;
-      switch (windows_process.handle_exception (ourstatus, debug_exceptions))
+      switch (windows_process.handle_exception (*current_event,
+						ourstatus, debug_exceptions))
 	{
 	case HANDLE_EXCEPTION_UNHANDLED:
 	default:
@@ -1775,7 +1776,8 @@  windows_nat_target::get_windows_debug_event
 		    "OUTPUT_DEBUG_STRING_EVENT");
       if (windows_process.saw_create != 1)
 	break;
-      thread_id = windows_process.handle_output_debug_string (ourstatus);
+      thread_id = windows_process.handle_output_debug_string (*current_event,
+							      ourstatus);
       break;
 
     default:
@@ -1800,6 +1802,8 @@  windows_nat_target::get_windows_debug_event
   const ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0);
   windows_thread_info *th = windows_process.find_thread (ptid);
 
+  th->last_event = *current_event;
+
   if (th->suspended)
     {
       /* Pending stop.  See the comment by the definition of
@@ -1818,8 +1822,8 @@  windows_nat_target::get_windows_debug_event
 	  th->stopped_at_software_breakpoint = true;
 	  th->pc_adjusted = false;
 	}
+
       th->pending_stop.status = *ourstatus;
-      th->pending_stop.event = *current_event;
       ourstatus->set_ignore ();
 
       continue_last_debug_event_main_thread
@@ -1845,7 +1849,10 @@  windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
   while (1)
     {
-      ptid_t result = get_windows_debug_event (pid, ourstatus, options);
+      DEBUG_EVENT current_event;
+
+      ptid_t result = get_windows_debug_event (pid, ourstatus, options,
+					       &current_event);
 
       if ((options & TARGET_WNOHANG) != 0
 	  && ourstatus->kind () == TARGET_WAITKIND_IGNORE)
@@ -1864,11 +1871,11 @@  windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	      windows_thread_info *th = windows_process.find_thread (result);
 
 	      th->stopped_at_software_breakpoint = false;
-	      if (windows_process.current_event.dwDebugEventCode
+	      if (current_event.dwDebugEventCode
 		  == EXCEPTION_DEBUG_EVENT
-		  && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
+		  && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
 		       == EXCEPTION_BREAKPOINT)
-		      || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
+		      || (current_event.u.Exception.ExceptionRecord.ExceptionCode
 			  == STATUS_WX86_BREAKPOINT))
 		  && windows_process.windows_initialization_done)
 		{
@@ -1909,8 +1916,6 @@  windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
   windows_process.cygwin_load_end = 0;
 #endif
   windows_process.process_id = pid;
-  memset (&windows_process.current_event, 0,
-	  sizeof (windows_process.current_event));
   inf = current_inferior ();
   if (!inf->target_is_pushed (this))
     inf->push_target (this);
@@ -1957,7 +1962,10 @@  windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
 	  && status.kind () != TARGET_WAITKIND_SPURIOUS)
 	break;
 
-      this->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
+      /* Don't use windows_nat_target::resume here because that
+	 assumes that inferior_ptid points at a valid thread, and we
+	 haven't switched to any thread yet.  */
+      windows_continue (DBG_CONTINUE, -1);
     }
 
   switch_to_thread (this->find_thread (last_ptid));
@@ -2233,7 +2241,7 @@  windows_nat_target::detach (inferior *inf, int from_tty)
   if (process_alive)
     do_synchronously ([&] ()
       {
-	if (!DebugActiveProcessStop (windows_process.current_event.dwProcessId))
+	if (!DebugActiveProcessStop (windows_process.process_id))
 	  err = (unsigned) GetLastError ();
 	else
 	  DebugSetProcessKillOnExit (FALSE);
@@ -2244,7 +2252,7 @@  windows_nat_target::detach (inferior *inf, int from_tty)
     {
       std::string msg
 	= string_printf (_("Can't detach process %u"),
-			 (unsigned) windows_process.current_event.dwProcessId);
+			 windows_process.process_id);
       throw_winerror_with_name (msg.c_str (), *err);
     }
 
@@ -3041,9 +3049,9 @@  windows_nat_target::kill ()
     {
       if (!windows_continue (DBG_CONTINUE, -1, WCONT_KILLED))
 	break;
-      wait_for_debug_event_main_thread (&windows_process.current_event);
-      if (windows_process.current_event.dwDebugEventCode
-	  == EXIT_PROCESS_DEBUG_EVENT)
+      DEBUG_EVENT current_event;
+      wait_for_debug_event_main_thread (&current_event);
+      if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
 	break;
     }
 
diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc
index 99a6150599e..5608fb902b1 100644
--- a/gdbserver/win32-low.cc
+++ b/gdbserver/win32-low.cc
@@ -309,9 +309,6 @@  do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
 
   windows_process.open_process_used = true;
 
-  memset (&windows_process.current_event, 0,
-	  sizeof (windows_process.current_event));
-
 #ifdef __x86_64__
   BOOL wow64;
   if (!IsWow64Process (proch, &wow64))
@@ -622,7 +619,8 @@  win32_process_target::attach (unsigned long pid)
 
 DWORD
 gdbserver_windows_process::handle_output_debug_string
-     (struct target_waitstatus *ourstatus)
+  (const DEBUG_EVENT &current_event,
+   struct target_waitstatus *ourstatus)
 {
 #define READ_BUFFER_LEN 1024
   CORE_ADDR addr;
@@ -691,14 +689,13 @@  win32_process_target::kill (process_info *process)
     {
       if (!child_continue_for_kill (DBG_CONTINUE, -1))
 	break;
-      if (!wait_for_debug_event (&windows_process.current_event, INFINITE))
+      DEBUG_EVENT current_event;
+      if (!wait_for_debug_event (&current_event, INFINITE))
 	break;
-      if (windows_process.current_event.dwDebugEventCode
-	  == EXIT_PROCESS_DEBUG_EVENT)
+      if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
 	break;
-      else if (windows_process.current_event.dwDebugEventCode
-	       == OUTPUT_DEBUG_STRING_EVENT)
-	windows_process.handle_output_debug_string (nullptr);
+      else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
+	windows_process.handle_output_debug_string (current_event, nullptr);
     }
 
   win32_clear_inferiors ();
@@ -772,8 +769,7 @@  resume_one_thread (thread_info *thread, bool step, gdb_signal sig,
 	  OUTMSG (("Cannot continue with signal %d here.  "
 		   "Not last-event thread", sig));
 	}
-      else if (windows_process.current_event.dwDebugEventCode
-	       != EXCEPTION_DEBUG_EVENT)
+      else if (th->last_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
 	{
 	  OUTMSG (("Cannot continue with signal %s here.  "
 		   "Not stopped for EXCEPTION_DEBUG_EVENT.\n",
@@ -918,7 +914,7 @@  gdbserver_windows_process::handle_load_dll (const char *name, LPVOID base)
 /* See nat/windows-nat.h.  */
 
 void
-gdbserver_windows_process::handle_unload_dll ()
+gdbserver_windows_process::handle_unload_dll (const DEBUG_EVENT &current_event)
 {
   CORE_ADDR load_addr =
 	  (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
@@ -952,7 +948,7 @@  gdbserver_windows_process::handle_access_violation
    PC.  */
 
 static void
-maybe_adjust_pc ()
+maybe_adjust_pc (const DEBUG_EVENT &current_event)
 {
   struct regcache *regcache = get_thread_regcache (current_thread, 1);
   child_fetch_inferior_registers (regcache, -1);
@@ -961,10 +957,10 @@  maybe_adjust_pc ()
     = windows_process.find_thread (current_thread_ptid ());
   th->stopped_at_software_breakpoint = false;
 
-  if (windows_process.current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
-      && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
+  if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+      && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
 	   == EXCEPTION_BREAKPOINT)
-	  || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
+	  || (current_event.u.Exception.ExceptionRecord.ExceptionCode
 	      == STATUS_WX86_BREAKPOINT))
       && windows_process.child_initialization_done)
     {
@@ -979,7 +975,8 @@  maybe_adjust_pc ()
 
 static int
 get_child_debug_event (DWORD *continue_status,
-		       struct target_waitstatus *ourstatus)
+		       struct target_waitstatus *ourstatus,
+		       DEBUG_EVENT *current_event)
 {
   ptid_t ptid;
 
@@ -990,8 +987,6 @@  get_child_debug_event (DWORD *continue_status,
   /* Check if GDB sent us an interrupt request.  */
   check_remote_input_interrupt_request ();
 
-  DEBUG_EVENT *current_event = &windows_process.current_event;
-
   windows_process.attaching = 0;
   {
     for (thread_info *thread : all_threads)
@@ -1003,8 +998,8 @@  get_child_debug_event (DWORD *continue_status,
 	  {
 	    *ourstatus = th->pending_stop.status;
 	    th->pending_stop.status.set_ignore ();
-	    windows_process.current_event = th->pending_stop.event;
-	    ptid = debug_event_ptid (&windows_process.current_event);
+	    *current_event = th->last_event;
+	    ptid = debug_event_ptid (current_event);
 	    switch_to_thread (find_thread_ptid (ptid));
 	    return 1;
 	  }
@@ -1013,7 +1008,7 @@  get_child_debug_event (DWORD *continue_status,
     /* Keep the wait time low enough for comfortable remote
        interruption, but high enough so gdbserver doesn't become a
        bottleneck.  */
-    if (!wait_for_debug_event (&windows_process.current_event, 250))
+    if (!wait_for_debug_event (current_event, 250))
       {
 	DWORD e  = GetLastError();
 
@@ -1108,7 +1103,7 @@  get_child_debug_event (DWORD *continue_status,
       CloseHandle (current_event->u.LoadDll.hFile);
       if (! windows_process.child_initialization_done)
 	break;
-      windows_process.dll_loaded_event ();
+      windows_process.dll_loaded_event (*current_event);
 
       ourstatus->set_loaded ();
       break;
@@ -1120,7 +1115,7 @@  get_child_debug_event (DWORD *continue_status,
 		(unsigned) current_event->dwThreadId));
       if (! windows_process.child_initialization_done)
 	break;
-      windows_process.handle_unload_dll ();
+      windows_process.handle_unload_dll (*current_event);
       ourstatus->set_loaded ();
       break;
 
@@ -1129,7 +1124,8 @@  get_child_debug_event (DWORD *continue_status,
 		"for pid=%u tid=%x\n",
 		(unsigned) current_event->dwProcessId,
 		(unsigned) current_event->dwThreadId));
-      if (windows_process.handle_exception (ourstatus, debug_threads)
+      if (windows_process.handle_exception (*current_event,
+					    ourstatus, debug_threads)
 	  == HANDLE_EXCEPTION_UNHANDLED)
 	*continue_status = DBG_EXCEPTION_NOT_HANDLED;
       break;
@@ -1140,7 +1136,7 @@  get_child_debug_event (DWORD *continue_status,
 		"for pid=%u tid=%x\n",
 		(unsigned) current_event->dwProcessId,
 		(unsigned) current_event->dwThreadId));
-      windows_process.handle_output_debug_string (nullptr);
+      windows_process.handle_output_debug_string (*current_event, nullptr);
       break;
 
     default:
@@ -1152,10 +1148,12 @@  get_child_debug_event (DWORD *continue_status,
       break;
     }
 
-  ptid = debug_event_ptid (&windows_process.current_event);
+  ptid = debug_event_ptid (current_event);
 
   windows_thread_info *th = windows_process.find_thread (ptid);
 
+  th->last_event = *current_event;
+
   if (th != nullptr && th->suspended)
     {
       /* Pending stop.  See the comment by the definition of
@@ -1164,9 +1162,8 @@  get_child_debug_event (DWORD *continue_status,
       OUTMSG2 (("get_windows_debug_event - "
 		"unexpected stop in suspended thread 0x%x\n",
 		th->tid));
-      maybe_adjust_pc ();
+      maybe_adjust_pc (*current_event);
       th->pending_stop.status = *ourstatus;
-      th->pending_stop.event = *current_event;
       ourstatus->set_spurious ();
     }
   else
@@ -1190,13 +1187,16 @@  win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
 	 fails).  Report it now.  */
       *ourstatus = windows_process.cached_status;
       windows_process.cached_status.set_ignore ();
-      return debug_event_ptid (&windows_process.current_event);
+      return ptid_t (windows_process.process_id,
+		     windows_process.main_thread_id, 0);
     }
 
   while (1)
     {
       DWORD continue_status;
-      if (!get_child_debug_event (&continue_status, ourstatus))
+      DEBUG_EVENT current_event;
+      if (!get_child_debug_event (&continue_status, ourstatus,
+				  &current_event))
 	continue;
 
       switch (ourstatus->kind ())
@@ -1205,20 +1205,20 @@  win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
 	  OUTMSG2 (("Child exited with retcode = %x\n",
 		    ourstatus->exit_status ()));
 	  win32_clear_inferiors ();
-	  return ptid_t (windows_process.current_event.dwProcessId);
+	  return ptid_t (windows_process.process_id);
 	case TARGET_WAITKIND_STOPPED:
 	case TARGET_WAITKIND_SIGNALLED:
 	case TARGET_WAITKIND_LOADED:
 	  {
 	    OUTMSG2 (("Child Stopped with signal = %d \n",
 		      ourstatus->sig ()));
-	    maybe_adjust_pc ();
+	    maybe_adjust_pc (current_event);
 
 	    /* All-stop, suspend all threads until they are explicitly
 	       resumed.  */
 	    for_each_thread (suspend_one_thread);
 
-	    return debug_event_ptid (&windows_process.current_event);
+	    return debug_event_ptid (&current_event);
 	  }
 	default:
 	  OUTMSG (("Ignoring unknown internal event, %d\n",
diff --git a/gdbserver/win32-low.h b/gdbserver/win32-low.h
index 4d26b87d73d..e99e47ea829 100644
--- a/gdbserver/win32-low.h
+++ b/gdbserver/win32-low.h
@@ -175,9 +175,10 @@  class win32_process_target : public process_stratum_target
 struct gdbserver_windows_process : public windows_nat::windows_process_info
 {
   windows_nat::windows_thread_info *find_thread (ptid_t ptid) override;
-  DWORD handle_output_debug_string (struct target_waitstatus *ourstatus) override;
+  DWORD handle_output_debug_string (const DEBUG_EVENT &current_event,
+				    struct target_waitstatus *ourstatus) override;
   void handle_load_dll (const char *dll_name, LPVOID base) override;
-  void handle_unload_dll () override;
+  void handle_unload_dll (const DEBUG_EVENT &current_event) override;
   bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
 
   int attaching = 0;