PowerPC64 DT_RELR ELFv1
[binutils-gdb.git] / gdbserver / win32-low.cc
index 46f0ddd58b811b0499f0fcb6dfee82b61b6abda8..e19bc2bd6e8501298048f2ec3d5d9c4696906833 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level interface to Windows debugging, for gdbserver.
-   Copyright (C) 2006-2020 Free Software Foundation, Inc.
+   Copyright (C) 2006-2022 Free Software Foundation, Inc.
 
    Contributed by Leo Zayas.  Based on "win32-nat.c" from GDB.
 
@@ -36,6 +36,8 @@
 #include "gdbsupport/common-inferior.h"
 #include "gdbsupport/gdb_wait.h"
 
+using namespace windows_nat;
+
 #ifndef USE_WIN32API
 #include <sys/cygwin.h>
 #endif
 #define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
 #endif
 
-#ifdef _WIN32_WCE
-# define GETPROCADDRESS(DLL, PROC) \
-  ((winapi_ ## PROC) GetProcAddress (DLL, TEXT (#PROC)))
-#else
-# define GETPROCADDRESS(DLL, PROC) \
-  ((winapi_ ## PROC) GetProcAddress (DLL, #PROC))
-#endif
-
 int using_threads = 1;
 
 /* Globals.  */
 static int attaching = 0;
-static HANDLE current_process_handle = NULL;
-static DWORD current_process_id = 0;
-static DWORD main_thread_id = 0;
-static EXCEPTION_RECORD siginfo_er;    /* Contents of $_siginfo */
-static enum gdb_signal last_sig = GDB_SIGNAL_0;
-
-/* The current debug event from WaitForDebugEvent.  */
-static DEBUG_EVENT current_event;
 
 /* A status that hasn't been reported to the core yet, and so
    win32_wait should return it next, instead of fetching the next
@@ -94,22 +80,16 @@ static int soft_interrupt_requested = 0;
    by suspending all the threads.  */
 static int faked_breakpoint = 0;
 
-const struct target_desc *win32_tdesc;
-
-#define NUM_REGS (the_low_target.num_regs)
+/* True if current_process_handle needs to be closed.  */
+static bool open_process_used = false;
 
-typedef BOOL (WINAPI *winapi_DebugActiveProcessStop) (DWORD dwProcessId);
-typedef BOOL (WINAPI *winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit);
-typedef BOOL (WINAPI *winapi_DebugBreakProcess) (HANDLE);
-typedef BOOL (WINAPI *winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD);
-
-static ptid_t win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
-                         int options);
-static void win32_resume (struct thread_resume *resume_info, size_t n);
-#ifndef _WIN32_WCE
-static void win32_add_all_dlls (void);
+const struct target_desc *win32_tdesc;
+#ifdef __x86_64__
+const struct target_desc *wow64_win32_tdesc;
 #endif
 
+#define NUM_REGS (the_low_target.num_regs ())
+
 /* Get the thread ID from the current selected inferior (the current
    thread).  */
 static ptid_t
@@ -128,32 +108,26 @@ debug_event_ptid (DEBUG_EVENT *event)
 /* Get the thread context of the thread associated with TH.  */
 
 static void
-win32_get_thread_context (win32_thread_info *th)
+win32_get_thread_context (windows_thread_info *th)
 {
-  memset (&th->context, 0, sizeof (CONTEXT));
-  (*the_low_target.get_thread_context) (th);
-#ifdef _WIN32_WCE
-  memcpy (&th->base_context, &th->context, sizeof (CONTEXT));
+#ifdef __x86_64__
+  if (wow64_process)
+    memset (&th->wow64_context, 0, sizeof (WOW64_CONTEXT));
+  else
 #endif
+    memset (&th->context, 0, sizeof (CONTEXT));
+  (*the_low_target.get_thread_context) (th);
 }
 
 /* Set the thread context of the thread associated with TH.  */
 
 static void
-win32_set_thread_context (win32_thread_info *th)
+win32_set_thread_context (windows_thread_info *th)
 {
-#ifdef _WIN32_WCE
-  /* Calling SuspendThread on a thread that is running kernel code
-     will report that the suspending was successful, but in fact, that
-     will often not be true.  In those cases, the context returned by
-     GetThreadContext will not be correct by the time the thread
-     stops, hence we can't set that context back into the thread when
-     resuming - it will most likely crash the inferior.
-     Unfortunately, there is no way to know when the thread will
-     really stop.  To work around it, we'll only write the context
-     back to the thread when either the user or GDB explicitly change
-     it between stopping and resuming.  */
-  if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0)
+#ifdef __x86_64__
+  if (wow64_process)
+    Wow64SetThreadContext (th->h, &th->wow64_context);
+  else
 #endif
     SetThreadContext (th->h, &th->context);
 }
@@ -161,7 +135,7 @@ win32_set_thread_context (win32_thread_info *th)
 /* Set the thread context of the thread associated with TH.  */
 
 static void
-win32_prepare_to_resume (win32_thread_info *th)
+win32_prepare_to_resume (windows_thread_info *th)
 {
   if (the_low_target.prepare_to_resume != NULL)
     (*the_low_target.prepare_to_resume) (th);
@@ -170,55 +144,55 @@ win32_prepare_to_resume (win32_thread_info *th)
 /* See win32-low.h.  */
 
 void
-win32_require_context (win32_thread_info *th)
+win32_require_context (windows_thread_info *th)
 {
-  if (th->context.ContextFlags == 0)
+  DWORD context_flags;
+#ifdef __x86_64__
+  if (wow64_process)
+    context_flags = th->wow64_context.ContextFlags;
+  else
+#endif
+    context_flags = th->context.ContextFlags;
+  if (context_flags == 0)
     {
-      if (!th->suspended)
-       {
-         if (SuspendThread (th->h) == (DWORD) -1)
-           {
-             DWORD err = GetLastError ();
-             OUTMSG (("warning: SuspendThread failed in thread_rec, "
-                      "(error %d): %s\n", (int) err, strwinerror (err)));
-           }
-         else
-           th->suspended = 1;
-       }
-
+      th->suspend ();
       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)
+/* See nat/windows-nat.h.  */
+
+windows_thread_info *
+windows_nat::thread_rec (ptid_t ptid, thread_disposition_type disposition)
 {
   thread_info *thread = find_thread_ptid (ptid);
   if (thread == NULL)
     return NULL;
 
-  win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
-  if (get_context)
+  windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
+  if (disposition != DONT_INVALIDATE_CONTEXT)
     win32_require_context (th);
   return th;
 }
 
 /* Add a thread to the thread list.  */
-static win32_thread_info *
+static windows_thread_info *
 child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
 {
-  win32_thread_info *th;
+  windows_thread_info *th;
   ptid_t ptid = ptid_t (pid, tid, 0);
 
-  if ((th = thread_rec (ptid, FALSE)))
+  if ((th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
     return th;
 
-  th = XCNEW (win32_thread_info);
-  th->tid = tid;
-  th->h = h;
-  th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
+  CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
+#ifdef __x86_64__
+  /* For WOW64 processes, this is actually the pointer to the 64bit TIB,
+     and the 32bit TIB is exactly 2 pages after it.  */
+  if (wow64_process)
+    base += 2 * 4096; /* page size = 4096 */
+#endif
+  th = new windows_thread_info (tid, h, base);
 
   add_thread (ptid, th);
 
@@ -232,11 +206,10 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
 static void
 delete_thread_info (thread_info *thread)
 {
-  win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
+  windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
 
   remove_thread (thread);
-  CloseHandle (th->h);
-  free (th);
+  delete th;
 }
 
 /* Delete a thread from the list of threads.  */
@@ -257,46 +230,51 @@ child_delete_thread (DWORD pid, DWORD tid)
 /* These watchpoint related wrapper functions simply pass on the function call
    if the low target has registered a corresponding function.  */
 
-static int
-win32_supports_z_point_type (char z_type)
+bool
+win32_process_target::supports_z_point_type (char z_type)
 {
-  return (the_low_target.supports_z_point_type != NULL
-         && the_low_target.supports_z_point_type (z_type));
+  return (z_type == Z_PACKET_SW_BP
+         || (the_low_target.supports_z_point_type != NULL
+             && the_low_target.supports_z_point_type (z_type)));
 }
 
-static int
-win32_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
-                   int size, struct raw_breakpoint *bp)
+int
+win32_process_target::insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                                   int size, raw_breakpoint *bp)
 {
-  if (the_low_target.insert_point != NULL)
+  if (type == raw_bkpt_type_sw)
+    return insert_memory_breakpoint (bp);
+  else if (the_low_target.insert_point != NULL)
     return the_low_target.insert_point (type, addr, size, bp);
   else
     /* Unsupported (see target.h).  */
     return 1;
 }
 
-static int
-win32_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
-                   int size, struct raw_breakpoint *bp)
+int
+win32_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                                   int size, raw_breakpoint *bp)
 {
-  if (the_low_target.remove_point != NULL)
+  if (type == raw_bkpt_type_sw)
+    return remove_memory_breakpoint (bp);
+  else if (the_low_target.remove_point != NULL)
     return the_low_target.remove_point (type, addr, size, bp);
   else
     /* Unsupported (see target.h).  */
     return 1;
 }
 
-static int
-win32_stopped_by_watchpoint (void)
+bool
+win32_process_target::stopped_by_watchpoint ()
 {
   if (the_low_target.stopped_by_watchpoint != NULL)
     return the_low_target.stopped_by_watchpoint ();
   else
-    return 0;
+    return false;
 }
 
-static CORE_ADDR
-win32_stopped_data_address (void)
+CORE_ADDR
+win32_process_target::stopped_data_address ()
 {
   if (the_low_target.stopped_data_address != NULL)
     return the_low_target.stopped_data_address ();
@@ -361,18 +339,42 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
 
   soft_interrupt_requested = 0;
   faked_breakpoint = 0;
+  open_process_used = true;
 
   memset (&current_event, 0, sizeof (current_event));
 
+#ifdef __x86_64__
+  BOOL wow64;
+  if (!IsWow64Process (proch, &wow64))
+    {
+      DWORD err = GetLastError ();
+      error ("Check if WOW64 process failed (error %d): %s\n",
+            (int) err, strwinerror (err));
+    }
+  wow64_process = wow64;
+
+  if (wow64_process
+      && (Wow64GetThreadContext == nullptr
+         || Wow64SetThreadContext == nullptr))
+    error ("WOW64 debugging is not supported on this system.\n");
+
+  ignore_first_breakpoint = !attached && wow64_process;
+#endif
+
   proc = add_process (pid, attached);
-  proc->tdesc = win32_tdesc;
+#ifdef __x86_64__
+  if (wow64_process)
+    proc->tdesc = wow64_win32_tdesc;
+  else
+#endif
+    proc->tdesc = win32_tdesc;
   child_init_thread_list ();
   child_initialization_done = 0;
 
   if (the_low_target.initial_stuff != NULL)
     (*the_low_target.initial_stuff) ();
 
-  cached_status.kind = TARGET_WAITKIND_IGNORE;
+  cached_status.set_ignore ();
 
   /* Flush all currently pending debug events (thread and dll list) up
      to the initial breakpoint.  */
@@ -380,10 +382,10 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
     {
       struct target_waitstatus status;
 
-      win32_wait (minus_one_ptid, &status, 0);
+      the_target->wait (minus_one_ptid, &status, 0);
 
       /* Note win32_wait doesn't return thread events.  */
-      if (status.kind != TARGET_WAITKIND_LOADED)
+      if (status.kind () != TARGET_WAITKIND_LOADED)
        {
          cached_status = status;
          break;
@@ -396,11 +398,10 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
        resume.kind = resume_continue;
        resume.sig = 0;
 
-       win32_resume (&resume, 1);
+       the_target->resume (&resume, 1);
       }
     }
 
-#ifndef _WIN32_WCE
   /* Now that the inferior has been started and all DLLs have been mapped,
      we can iterate over all DLLs and load them in.
 
@@ -416,8 +417,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
      Rather than try to work around this sort of issue, it is much
      simpler to just ignore DLL load/unload events during the startup
      phase, and then process them all in one batch now.  */
-  win32_add_all_dlls ();
-#endif
+  windows_add_all_dlls ();
 
   child_initialization_done = 1;
 }
@@ -427,7 +427,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
 static void
 continue_one_thread (thread_info *thread, int thread_id)
 {
-  win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
+  windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
 
   if (thread_id == -1 || thread_id == th->tid)
     {
@@ -435,19 +435,20 @@ continue_one_thread (thread_info *thread, int thread_id)
 
       if (th->suspended)
        {
-         if (th->context.ContextFlags)
+         DWORD *context_flags;
+#ifdef __x86_64__
+         if (wow64_process)
+           context_flags = &th->wow64_context.ContextFlags;
+         else
+#endif
+           context_flags = &th->context.ContextFlags;
+         if (*context_flags)
            {
              win32_set_thread_context (th);
-             th->context.ContextFlags = 0;
+             *context_flags = 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->resume ();
        }
     }
 }
@@ -455,6 +456,10 @@ continue_one_thread (thread_info *thread, int thread_id)
 static BOOL
 child_continue (DWORD continue_status, int thread_id)
 {
+  desired_stop_thread_id = thread_id;
+  if (matching_pending_stop (debug_threads))
+    return TRUE;
+
   /* The inferior will only continue after the ContinueDebugEvent
      call.  */
   for_each_thread ([&] (thread_info *thread)
@@ -463,12 +468,7 @@ child_continue (DWORD continue_status, int thread_id)
     });
   faked_breakpoint = 0;
 
-  if (!ContinueDebugEvent (current_event.dwProcessId,
-                          current_event.dwThreadId,
-                          continue_status))
-    return FALSE;
-
-  return TRUE;
+  return continue_last_debug_event (continue_status, debug_threads);
 }
 
 /* Fetch register(s) from the current thread context.  */
@@ -476,7 +476,8 @@ static void
 child_fetch_inferior_registers (struct regcache *regcache, int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
+  windows_thread_info *th = thread_rec (current_thread_ptid (),
+                                       INVALIDATE_CONTEXT);
   if (r == -1 || r > NUM_REGS)
     child_fetch_inferior_registers (regcache, NUM_REGS);
   else
@@ -490,7 +491,8 @@ static void
 child_store_inferior_registers (struct regcache *regcache, int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
+  windows_thread_info *th = thread_rec (current_thread_ptid (),
+                                       INVALIDATE_CONTEXT);
   if (r == -1 || r == 0 || r > NUM_REGS)
     child_store_inferior_registers (regcache, NUM_REGS);
   else
@@ -557,53 +559,13 @@ static BOOL
 create_process (const char *program, char *args,
                DWORD flags, PROCESS_INFORMATION *pi)
 {
-  const char *inferior_cwd = get_inferior_cwd ();
+  const std::string &inferior_cwd = get_inferior_cwd ();
   BOOL ret;
   size_t argslen, proglen;
 
   proglen = strlen (program) + 1;
   argslen = strlen (args) + proglen;
 
-#ifdef _WIN32_WCE
-  wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
-
-  wprogram = (wchar_t *) alloca (proglen * sizeof (wchar_t));
-  mbstowcs (wprogram, program, proglen);
-
-  for (p = wprogram; *p; ++p)
-    if (L'/' == *p)
-      *p = L'\\';
-
-  wargs = alloca ((argslen + 1) * sizeof (wchar_t));
-  wcscpy (wargs, wprogram);
-  wcscat (wargs, L" ");
-  mbstowcs (wargs + proglen, args, argslen + 1 - proglen);
-
-  if (inferior_cwd != NULL)
-    {
-      std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);
-      std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
-                   '/', '\\');
-      wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t));
-      if (mbstowcs (wcwd, expanded_infcwd.c_str (),
-                   expanded_infcwd.size () + 1) == NULL)
-       {
-         error (_("\
-Could not convert the expanded inferior cwd to wide-char."));
-       }
-    }
-
-  ret = CreateProcessW (wprogram, /* image name */
-                       wargs,    /* command line */
-                       NULL,     /* security, not supported */
-                       NULL,     /* thread, not supported */
-                       FALSE,    /* inherit handles, not supported */
-                       flags,    /* start flags */
-                       NULL,     /* environment, not supported */
-                       wcwd,     /* current directory */
-                       NULL,     /* start info, not supported */
-                       pi);      /* proc info */
-#else
   STARTUPINFOA si = { sizeof (STARTUPINFOA) };
   char *program_and_args = (char *) alloca (argslen + 1);
 
@@ -618,12 +580,11 @@ Could not convert the expanded inferior cwd to wide-char."));
                        flags,             /* start flags */
                        NULL,              /* environment */
                        /* current directory */
-                       (inferior_cwd == NULL
+                       (inferior_cwd.empty ()
                         ? NULL
-                        : gdb_tilde_expand (inferior_cwd).c_str()),
+                        : gdb_tilde_expand (inferior_cwd.c_str ()).c_str()),
                        &si,               /* start info */
                        pi);               /* proc info */
-#endif
 
   return ret;
 }
@@ -646,7 +607,7 @@ win32_process_target::create_inferior (const char *program,
   DWORD flags;
   PROCESS_INFORMATION pi;
   DWORD err;
-  std::string str_program_args = stringify_argv (program_args);
+  std::string str_program_args = construct_inferior_arguments (program_args);
   char *args = (char *) str_program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
@@ -704,18 +665,13 @@ win32_process_target::create_inferior (const char *program,
       OUTMSG2 (("Process created: %s %s\n", program, (char *) args));
     }
 
-#ifndef _WIN32_WCE
-  /* On Windows CE this handle can't be closed.  The OS reuses
-     it in the debug events, while the 9x/NT versions of Windows
-     probably use a DuplicateHandle'd one.  */
   CloseHandle (pi.hThread);
-#endif
 
   do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
 
   /* Wait till we are at 1st instruction in program, return new pid
      (assuming success).  */
-  cs.last_ptid = win32_wait (ptid_t (current_process_id), &cs.last_status, 0);
+  cs.last_ptid = wait (ptid_t (current_process_id), &cs.last_status, 0);
 
   /* Necessary for handle_v_kill.  */
   signal_pid = current_process_id;
@@ -730,22 +686,14 @@ int
 win32_process_target::attach (unsigned long pid)
 {
   HANDLE h;
-  winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
   DWORD err;
-#ifdef _WIN32_WCE
-  HMODULE dll = GetModuleHandle (_T("COREDLL.DLL"));
-#else
-  HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
-#endif
-  DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit);
 
   h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
   if (h != NULL)
     {
       if (DebugActiveProcess (pid))
        {
-         if (DebugSetProcessKillOnExit != NULL)
-           DebugSetProcessKillOnExit (FALSE);
+         DebugSetProcessKillOnExit (FALSE);
 
          /* win32_wait needs to know we're attaching.  */
          attaching = 1;
@@ -761,9 +709,10 @@ win32_process_target::attach (unsigned long pid)
         (int) err, strwinerror (err));
 }
 
-/* Handle OUTPUT_DEBUG_STRING_EVENT from child process.  */
-static void
-handle_output_debug_string (void)
+/* See nat/windows-nat.h.  */
+
+int
+windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus)
 {
 #define READ_BUFFER_LEN 1024
   CORE_ADDR addr;
@@ -771,7 +720,7 @@ handle_output_debug_string (void)
   DWORD nbytes = current_event.u.DebugString.nDebugStringLength;
 
   if (nbytes == 0)
-    return;
+    return 0;
 
   if (nbytes > READ_BUFFER_LEN)
     nbytes = READ_BUFFER_LEN;
@@ -784,13 +733,13 @@ handle_output_debug_string (void)
         in Unicode.  */
       WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 };
       if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0)
-       return;
+       return 0;
       wcstombs (s, buffer, (nbytes + 1) / sizeof (WCHAR));
     }
   else
     {
       if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0)
-       return;
+       return 0;
     }
 
   if (!startswith (s, "cYg"))
@@ -798,19 +747,24 @@ handle_output_debug_string (void)
       if (!server_waiting)
        {
          OUTMSG2(("%s", s));
-         return;
+         return 0;
        }
 
       monitor_output (s);
     }
 #undef READ_BUFFER_LEN
+
+  return 0;
 }
 
 static void
 win32_clear_inferiors (void)
 {
-  if (current_process_handle != NULL)
-    CloseHandle (current_process_handle);
+  if (open_process_used)
+    {
+      CloseHandle (current_process_handle);
+      open_process_used = false;
+    }
 
   for_each_thread (delete_thread_info);
   siginfo_er.ExceptionCode = 0;
@@ -827,12 +781,12 @@ win32_process_target::kill (process_info *process)
     {
       if (!child_continue (DBG_CONTINUE, -1))
        break;
-      if (!WaitForDebugEvent (&current_event, INFINITE))
+      if (!wait_for_debug_event (&current_event, INFINITE))
        break;
       if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
        break;
       else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
-       handle_output_debug_string ();
+       handle_output_debug_string (nullptr);
     }
 
   win32_clear_inferiors ();
@@ -846,27 +800,11 @@ win32_process_target::kill (process_info *process)
 int
 win32_process_target::detach (process_info *process)
 {
-  winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
-  winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
-#ifdef _WIN32_WCE
-  HMODULE dll = GetModuleHandle (_T("COREDLL.DLL"));
-#else
-  HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
-#endif
-  DebugActiveProcessStop = GETPROCADDRESS (dll, DebugActiveProcessStop);
-  DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit);
-
-  if (DebugSetProcessKillOnExit == NULL
-      || DebugActiveProcessStop == NULL)
-    return -1;
-
-  {
-    struct thread_resume resume;
-    resume.thread = minus_one_ptid;
-    resume.kind = resume_continue;
-    resume.sig = 0;
-    win32_resume (&resume, 1);
-  }
+  struct thread_resume resume;
+  resume.thread = minus_one_ptid;
+  resume.kind = resume_continue;
+  resume.sig = 0;
+  this->resume (&resume, 1);
 
   if (!DebugActiveProcessStop (current_process_id))
     return -1;
@@ -908,13 +846,13 @@ win32_process_target::thread_alive (ptid_t ptid)
 
 /* Resume the inferior process.  RESUME_INFO describes how we want
    to resume.  */
-static void
-win32_resume (struct thread_resume *resume_info, size_t n)
+void
+win32_process_target::resume (thread_resume *resume_info, size_t n)
 {
   DWORD tid;
   enum gdb_signal sig;
   int step;
-  win32_thread_info *th;
+  windows_thread_info *th;
   DWORD continue_status = DBG_CONTINUE;
   ptid_t ptid;
 
@@ -959,12 +897,19 @@ win32_resume (struct thread_resume *resume_info, size_t n)
 
   /* Get context for the currently selected thread.  */
   ptid = debug_event_ptid (&current_event);
-  th = thread_rec (ptid, FALSE);
+  th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
   if (th)
     {
       win32_prepare_to_resume (th);
 
-      if (th->context.ContextFlags)
+      DWORD *context_flags;
+#ifdef __x86_64__
+      if (wow64_process)
+       context_flags = &th->wow64_context.ContextFlags;
+      else
+#endif
+       context_flags = &th->context.ContextFlags;
+      if (*context_flags)
        {
          /* Move register values from the inferior into the thread
             context structure.  */
@@ -980,7 +925,7 @@ win32_resume (struct thread_resume *resume_info, size_t n)
            }
 
          win32_set_thread_context (th);
-         th->context.ContextFlags = 0;
+         *context_flags = 0;
        }
     }
 
@@ -990,21 +935,18 @@ win32_resume (struct thread_resume *resume_info, size_t n)
   child_continue (continue_status, tid);
 }
 
-static void
-win32_add_one_solib (const char *name, CORE_ADDR load_addr)
+/* See nat/windows-nat.h.  */
+
+void
+windows_nat::handle_load_dll (const char *name, LPVOID base)
 {
+  CORE_ADDR load_addr = (CORE_ADDR) (uintptr_t) base;
+
   char buf[MAX_PATH + 1];
   char buf2[MAX_PATH + 1];
 
-#ifdef _WIN32_WCE
-  WIN32_FIND_DATA w32_fd;
-  WCHAR wname[MAX_PATH + 1];
-  mbstowcs (wname, name, MAX_PATH);
-  HANDLE h = FindFirstFile (wname, &w32_fd);
-#else
   WIN32_FIND_DATAA w32_fd;
   HANDLE h = FindFirstFileA (name, &w32_fd);
-#endif
 
   /* The symbols in a dll are offset by 0x1000, which is the
      offset from 0 of the first byte in an image - because
@@ -1017,7 +959,6 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr)
     {
       FindClose (h);
       strcpy (buf, name);
-#ifndef _WIN32_WCE
       {
        char cwd[MAX_PATH + 1];
        char *p;
@@ -1031,16 +972,13 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr)
            SetCurrentDirectoryA (cwd);
          }
       }
-#endif
     }
 
-#ifndef _WIN32_WCE
   if (strcasecmp (buf, "ntdll.dll") == 0)
     {
       GetSystemDirectoryA (buf, sizeof (buf));
       strcat (buf, "\\ntdll.dll");
     }
-#endif
 
 #ifdef __CYGWIN__
   cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2));
@@ -1051,182 +989,10 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr)
   loaded_dll (buf2, load_addr);
 }
 
-static char *
-get_image_name (HANDLE h, void *address, int unicode)
-{
-  static char buf[(2 * MAX_PATH) + 1];
-  DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
-  char *address_ptr;
-  int len = 0;
-  char b[2];
-  SIZE_T done;
-
-  /* Attempt to read the name of the dll that was detected.
-     This is documented to work only when actively debugging
-     a program.  It will not work for attached processes. */
-  if (address == NULL)
-    return NULL;
-
-#ifdef _WIN32_WCE
-  /* Windows CE reports the address of the image name,
-     instead of an address of a pointer into the image name.  */
-  address_ptr = address;
-#else
-  /* See if we could read the address of a string, and that the
-     address isn't null. */
-  if (!ReadProcessMemory (h, address,  &address_ptr,
-                         sizeof (address_ptr), &done)
-      || done != sizeof (address_ptr)
-      || !address_ptr)
-    return NULL;
-#endif
-
-  /* Find the length of the string */
-  while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
-        && (b[0] != 0 || b[size - 1] != 0) && done == size)
-    continue;
-
-  if (!unicode)
-    ReadProcessMemory (h, address_ptr, buf, len, &done);
-  else
-    {
-      WCHAR *unicode_address = XALLOCAVEC (WCHAR, len);
-      ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
-                        &done);
-
-      WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0);
-    }
-
-  return buf;
-}
-
-typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *,
-                                                 DWORD, LPDWORD);
-typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE,
-                                                   LPMODULEINFO, DWORD);
-typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE,
-                                                    LPSTR, DWORD);
-
-static winapi_EnumProcessModules win32_EnumProcessModules;
-static winapi_GetModuleInformation win32_GetModuleInformation;
-static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA;
-
-static BOOL
-load_psapi (void)
-{
-  static int psapi_loaded = 0;
-  static HMODULE dll = NULL;
-
-  if (!psapi_loaded)
-    {
-      psapi_loaded = 1;
-      dll = LoadLibrary (TEXT("psapi.dll"));
-      if (!dll)
-       return FALSE;
-      win32_EnumProcessModules =
-             GETPROCADDRESS (dll, EnumProcessModules);
-      win32_GetModuleInformation =
-             GETPROCADDRESS (dll, GetModuleInformation);
-      win32_GetModuleFileNameExA =
-             GETPROCADDRESS (dll, GetModuleFileNameExA);
-    }
-
-  return (win32_EnumProcessModules != NULL
-         && win32_GetModuleInformation != NULL
-         && win32_GetModuleFileNameExA != NULL);
-}
-
-#ifndef _WIN32_WCE
-
-/* Iterate over all DLLs currently mapped by our inferior, and
-   add them to our list of solibs.  */
-
-static void
-win32_add_all_dlls (void)
-{
-  size_t i;
-  HMODULE dh_buf[1];
-  HMODULE *DllHandle = dh_buf;
-  DWORD cbNeeded;
-  BOOL ok;
-
-  if (!load_psapi ())
-    return;
-
-  cbNeeded = 0;
-  ok = (*win32_EnumProcessModules) (current_process_handle,
-                                   DllHandle,
-                                   sizeof (HMODULE),
-                                   &cbNeeded);
-
-  if (!ok || !cbNeeded)
-    return;
-
-  DllHandle = (HMODULE *) alloca (cbNeeded);
-  if (!DllHandle)
-    return;
-
-  ok = (*win32_EnumProcessModules) (current_process_handle,
-                                   DllHandle,
-                                   cbNeeded,
-                                   &cbNeeded);
-  if (!ok)
-    return;
+/* See nat/windows-nat.h.  */
 
-  for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
-    {
-      MODULEINFO mi;
-      char dll_name[MAX_PATH];
-
-      if (!(*win32_GetModuleInformation) (current_process_handle,
-                                         DllHandle[i],
-                                         &mi,
-                                         sizeof (mi)))
-       continue;
-      if ((*win32_GetModuleFileNameExA) (current_process_handle,
-                                        DllHandle[i],
-                                        dll_name,
-                                        MAX_PATH) == 0)
-       continue;
-      win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll);
-    }
-}
-#endif
-
-typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD);
-typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32);
-typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32);
-
-/* Handle a DLL load event.
-
-   This function assumes that this event did not occur during inferior
-   initialization, where their event info may be incomplete (see
-   do_initial_child_stuff and win32_add_all_dlls for more info on
-   how we handle DLL loading during that phase).  */
-
-static void
-handle_load_dll (void)
-{
-  LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
-  char *dll_name;
-
-  dll_name = get_image_name (current_process_handle,
-                            event->lpImageName, event->fUnicode);
-  if (!dll_name)
-    return;
-
-  win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll);
-}
-
-/* Handle a DLL unload event.
-
-   This function assumes that this event did not occur during inferior
-   initialization, where their event info may be incomplete (see
-   do_initial_child_stuff and win32_add_one_solib for more info
-   on how we handle DLL loading during that phase).  */
-
-static void
-handle_unload_dll (void)
+void
+windows_nat::handle_unload_dll ()
 {
   CORE_ADDR load_addr =
          (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
@@ -1238,133 +1004,12 @@ handle_unload_dll (void)
   unloaded_dll (NULL, load_addr);
 }
 
-static void
-handle_exception (struct target_waitstatus *ourstatus)
-{
-  DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
-
-  memcpy (&siginfo_er, &current_event.u.Exception.ExceptionRecord,
-         sizeof siginfo_er);
-
-  ourstatus->kind = TARGET_WAITKIND_STOPPED;
-
-  switch (code)
-    {
-    case EXCEPTION_ACCESS_VIOLATION:
-      OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
-      ourstatus->value.sig = GDB_SIGNAL_SEGV;
-      break;
-    case STATUS_STACK_OVERFLOW:
-      OUTMSG2 (("STATUS_STACK_OVERFLOW"));
-      ourstatus->value.sig = GDB_SIGNAL_SEGV;
-      break;
-    case STATUS_FLOAT_DENORMAL_OPERAND:
-      OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
-      OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_INEXACT_RESULT:
-      OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_INVALID_OPERATION:
-      OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_OVERFLOW:
-      OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_STACK_CHECK:
-      OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_UNDERFLOW:
-      OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_DIVIDE_BY_ZERO:
-      OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_INTEGER_DIVIDE_BY_ZERO:
-      OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_INTEGER_OVERFLOW:
-      OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case EXCEPTION_BREAKPOINT:
-      OUTMSG2 (("EXCEPTION_BREAKPOINT"));
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
-#ifdef _WIN32_WCE
-      /* Remove the initial breakpoint.  */
-      check_breakpoints ((CORE_ADDR) (long) current_event
-                        .u.Exception.ExceptionRecord.ExceptionAddress);
-#endif
-      break;
-    case DBG_CONTROL_C:
-      OUTMSG2 (("DBG_CONTROL_C"));
-      ourstatus->value.sig = GDB_SIGNAL_INT;
-      break;
-    case DBG_CONTROL_BREAK:
-      OUTMSG2 (("DBG_CONTROL_BREAK"));
-      ourstatus->value.sig = GDB_SIGNAL_INT;
-      break;
-    case EXCEPTION_SINGLE_STEP:
-      OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
-      break;
-    case EXCEPTION_ILLEGAL_INSTRUCTION:
-      OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
-      break;
-    case EXCEPTION_PRIV_INSTRUCTION:
-      OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
-      break;
-    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
-      OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
-      break;
-    default:
-      if (current_event.u.Exception.dwFirstChance)
-       {
-         ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-         return;
-       }
-      OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s",
-           (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
-           phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord.
-           ExceptionAddress, sizeof (uintptr_t))));
-      ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
-      break;
-    }
-  OUTMSG2 (("\n"));
-  last_sig = ourstatus->value.sig;
-}
-
-
 static void
 suspend_one_thread (thread_info *thread)
 {
-  win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
+  windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
 
-  if (!th->suspended)
-    {
-      if (SuspendThread (th->h) == (DWORD) -1)
-       {
-         DWORD err = GetLastError ();
-         OUTMSG (("warning: SuspendThread failed in suspend_one_thread, "
-                  "(error %d): %s\n", (int) err, strwinerror (err)));
-       }
-      else
-       th->suspended = 1;
-    }
+  th->suspend ();
 }
 
 static void
@@ -1383,23 +1028,61 @@ fake_breakpoint_event (void)
   for_each_thread (suspend_one_thread);
 }
 
-#ifdef _WIN32_WCE
-static int
-auto_delete_breakpoint (CORE_ADDR stop_pc)
+/* See nat/windows-nat.h.  */
+
+bool
+windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
 {
-  return 1;
+  return false;
+}
+
+/* See nat/windows-nat.h.  */
+
+bool
+windows_nat::handle_access_violation (const EXCEPTION_RECORD *rec)
+{
+  return false;
+}
+
+/* A helper function that will, if needed, set
+   'stopped_at_software_breakpoint' on the thread and adjust the
+   PC.  */
+
+static void
+maybe_adjust_pc ()
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 1);
+  child_fetch_inferior_registers (regcache, -1);
+
+  windows_thread_info *th = thread_rec (current_thread_ptid (),
+                                       DONT_INVALIDATE_CONTEXT);
+  th->stopped_at_software_breakpoint = false;
+
+  if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+      && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
+          == EXCEPTION_BREAKPOINT)
+         || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+             == STATUS_WX86_BREAKPOINT))
+      && child_initialization_done)
+    {
+      th->stopped_at_software_breakpoint = true;
+      CORE_ADDR pc = regcache_read_pc (regcache);
+      CORE_ADDR sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break;
+      regcache_write_pc (regcache, sw_breakpoint_pc);
+    }
 }
-#endif
 
 /* Get the next event from the child.  */
 
 static int
-get_child_debug_event (struct target_waitstatus *ourstatus)
+get_child_debug_event (DWORD *continue_status,
+                      struct target_waitstatus *ourstatus)
 {
   ptid_t ptid;
 
   last_sig = GDB_SIGNAL_0;
-  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  ourstatus->set_spurious ();
+  *continue_status = DBG_CONTINUE;
 
   /* Check if GDB sent us an interrupt request.  */
   check_remote_input_interrupt_request ();
@@ -1411,59 +1094,38 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       goto gotevent;
     }
 
-#ifndef _WIN32_WCE
   attaching = 0;
-#else
-  if (attaching)
-    {
-      /* WinCE doesn't set an initial breakpoint automatically.  To
-        stop the inferior, we flush all currently pending debug
-        events -- the thread list and the dll list are always
-        reported immediatelly without delay, then, we suspend all
-        threads and pretend we saw a trap at the current PC of the
-        main thread.
-
-        Contrary to desktop Windows, Windows CE *does* report the dll
-        names on LOAD_DLL_DEBUG_EVENTs resulting from a
-        DebugActiveProcess call.  This limits the way we can detect
-        if all the dlls have already been reported.  If we get a real
-        debug event before leaving attaching, the worst that will
-        happen is the user will see a spurious breakpoint.  */
-
-      current_event.dwDebugEventCode = 0;
-      if (!WaitForDebugEvent (&current_event, 0))
-       {
-         OUTMSG2(("no attach events left\n"));
-         fake_breakpoint_event ();
-         attaching = 0;
-       }
-      else
-       OUTMSG2(("got attach event\n"));
-    }
-  else
-#endif
-    {
-      /* Keep the wait time low enough for comfortable remote
-        interruption, but high enough so gdbserver doesn't become a
-        bottleneck.  */
-      if (!WaitForDebugEvent (&current_event, 250))
-        {
-         DWORD e  = GetLastError();
-
-         if (e == ERROR_PIPE_NOT_CONNECTED)
-           {
-             /* This will happen if the loader fails to succesfully
-                load the application, e.g., if the main executable
-                tries to pull in a non-existing export from a
-                DLL.  */
-             ourstatus->kind = TARGET_WAITKIND_EXITED;
-             ourstatus->value.integer = 1;
-             return 1;
-           }
+  {
+    gdb::optional<pending_stop> stop = fetch_pending_stop (debug_threads);
+    if (stop.has_value ())
+      {
+       *ourstatus = stop->status;
+       current_event = stop->event;
+       ptid = debug_event_ptid (&current_event);
+       switch_to_thread (find_thread_ptid (ptid));
+       return 1;
+      }
 
-         return 0;
-        }
-    }
+    /* 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 (&current_event, 250))
+      {
+       DWORD e  = GetLastError();
+
+       if (e == ERROR_PIPE_NOT_CONNECTED)
+         {
+           /* This will happen if the loader fails to succesfully
+              load the application, e.g., if the main executable
+              tries to pull in a non-existing export from a
+              DLL.  */
+           ourstatus->set_exited (1);
+           return 1;
+         }
+
+       return 0;
+      }
+  }
 
  gotevent:
 
@@ -1490,7 +1152,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       child_delete_thread (current_event.dwProcessId,
                           current_event.dwThreadId);
 
-      current_thread = get_first_thread ();
+      switch_to_thread (get_first_thread ());
       return 1;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1500,6 +1162,12 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                (unsigned) current_event.dwThreadId));
       CloseHandle (current_event.u.CreateProcessInfo.hFile);
 
+      if (open_process_used)
+       {
+         CloseHandle (current_process_handle);
+         open_process_used = false;
+       }
+
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
       main_thread_id = current_event.dwThreadId;
 
@@ -1508,19 +1176,6 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                        main_thread_id,
                        current_event.u.CreateProcessInfo.hThread,
                        current_event.u.CreateProcessInfo.lpThreadLocalBase);
-
-#ifdef _WIN32_WCE
-      if (!attaching)
-       {
-         /* Windows CE doesn't set the initial breakpoint
-            automatically like the desktop versions of Windows do.
-            We add it explicitly here.  It will be removed as soon as
-            it is hit.  */
-         set_breakpoint_at ((CORE_ADDR) (long) current_event.u
-                            .CreateProcessInfo.lpStartAddress,
-                            auto_delete_breakpoint);
-       }
-#endif
       break;
 
     case EXIT_PROCESS_DEBUG_EVENT:
@@ -1536,19 +1191,11 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
        int exit_signal
          = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1;
        if (exit_signal == -1)
-         {
-           ourstatus->kind = TARGET_WAITKIND_EXITED;
-           ourstatus->value.integer = exit_status;
-         }
+         ourstatus->set_exited (exit_status);
        else
-         {
-           ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-           ourstatus->value.sig = gdb_signal_from_host (exit_signal);
-         }
+         ourstatus->set_signalled (gdb_signal_from_host (exit_signal));
       }
-      child_continue (DBG_CONTINUE, -1);
-      CloseHandle (current_process_handle);
-      current_process_handle = NULL;
+      child_continue (DBG_CONTINUE, desired_stop_thread_id);
       break;
 
     case LOAD_DLL_DEBUG_EVENT:
@@ -1559,10 +1206,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       CloseHandle (current_event.u.LoadDll.hFile);
       if (! child_initialization_done)
        break;
-      handle_load_dll ();
+      dll_loaded_event ();
 
-      ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
+      ourstatus->set_loaded ();
       break;
 
     case UNLOAD_DLL_DEBUG_EVENT:
@@ -1573,8 +1219,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       if (! child_initialization_done)
        break;
       handle_unload_dll ();
-      ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
+      ourstatus->set_loaded ();
       break;
 
     case EXCEPTION_DEBUG_EVENT:
@@ -1582,7 +1227,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%u tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
-      handle_exception (ourstatus);
+      if (handle_exception (ourstatus, debug_threads)
+         == HANDLE_EXCEPTION_UNHANDLED)
+       *continue_status = DBG_EXCEPTION_NOT_HANDLED;
       break;
 
     case OUTPUT_DEBUG_STRING_EVENT:
@@ -1591,7 +1238,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%u tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
-      handle_output_debug_string ();
+      handle_output_debug_string (nullptr);
       break;
 
     default:
@@ -1604,56 +1251,71 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
     }
 
   ptid = debug_event_ptid (&current_event);
-  current_thread = find_thread_ptid (ptid);
+
+  if (desired_stop_thread_id != -1 && desired_stop_thread_id != ptid.lwp ())
+    {
+      /* Pending stop.  See the comment by the definition of
+        "pending_stops" for details on why this is needed.  */
+      OUTMSG2 (("get_windows_debug_event - "
+               "unexpected stop in 0x%lx (expecting 0x%x)\n",
+               ptid.lwp (), desired_stop_thread_id));
+      maybe_adjust_pc ();
+      pending_stops.push_back ({(DWORD) ptid.lwp (), *ourstatus, current_event});
+      ourstatus->set_spurious ();
+    }
+  else
+    switch_to_thread (find_thread_ptid (ptid));
+
   return 1;
 }
 
 /* Wait for the inferior process to change state.
    STATUS will be filled in with a response code to send to GDB.
    Returns the signal which caused the process to stop. */
-static ptid_t
-win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
+ptid_t
+win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
+                           target_wait_flags options)
 {
-  struct regcache *regcache;
-
-  if (cached_status.kind != TARGET_WAITKIND_IGNORE)
+  if (cached_status.kind () != TARGET_WAITKIND_IGNORE)
     {
       /* The core always does a wait after creating the inferior, and
         do_initial_child_stuff already ran the inferior to the
         initial breakpoint (or an exit, if creating the process
         fails).  Report it now.  */
       *ourstatus = cached_status;
-      cached_status.kind = TARGET_WAITKIND_IGNORE;
+      cached_status.set_ignore ();
       return debug_event_ptid (&current_event);
     }
 
   while (1)
     {
-      if (!get_child_debug_event (ourstatus))
+      DWORD continue_status;
+      if (!get_child_debug_event (&continue_status, ourstatus))
        continue;
 
-      switch (ourstatus->kind)
+      switch (ourstatus->kind ())
        {
        case TARGET_WAITKIND_EXITED:
          OUTMSG2 (("Child exited with retcode = %x\n",
-                   ourstatus->value.integer));
+                   ourstatus->exit_status ()));
          win32_clear_inferiors ();
          return ptid_t (current_event.dwProcessId);
        case TARGET_WAITKIND_STOPPED:
        case TARGET_WAITKIND_SIGNALLED:
        case TARGET_WAITKIND_LOADED:
-         OUTMSG2 (("Child Stopped with signal = %d \n",
-                   ourstatus->value.sig));
-
-         regcache = get_thread_regcache (current_thread, 1);
-         child_fetch_inferior_registers (regcache, -1);
-         return debug_event_ptid (&current_event);
+         {
+           OUTMSG2 (("Child Stopped with signal = %d \n",
+                     ourstatus->sig ()));
+           maybe_adjust_pc ();
+           return debug_event_ptid (&current_event);
+         }
        default:
-         OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
+         OUTMSG (("Ignoring unknown internal event, %d\n",
+                 ourstatus->kind ()));
          /* fall-through */
        case TARGET_WAITKIND_SPURIOUS:
          /* do nothing, just continue */
-         child_continue (DBG_CONTINUE, -1);
+         child_continue (continue_status, desired_stop_thread_id);
          break;
        }
     }
@@ -1661,16 +1323,16 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 
 /* Fetch registers from the inferior process.
    If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO.  */
-static void
-win32_fetch_inferior_registers (struct regcache *regcache, int regno)
+void
+win32_process_target::fetch_registers (regcache *regcache, int regno)
 {
   child_fetch_inferior_registers (regcache, regno);
 }
 
 /* Store registers to the inferior process.
    If REGNO is -1, store all registers; otherwise, store at least REGNO.  */
-static void
-win32_store_inferior_registers (struct regcache *regcache, int regno)
+void
+win32_process_target::store_registers (regcache *regcache, int regno)
 {
   child_store_inferior_registers (regcache, regno);
 }
@@ -1678,8 +1340,9 @@ win32_store_inferior_registers (struct regcache *regcache, int regno)
 /* Read memory from the inferior process.  This should generally be
    called through read_inferior_memory, which handles breakpoint shadowing.
    Read LEN bytes at MEMADDR into a buffer at MYADDR.  */
-static int
-win32_read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+int
+win32_process_target::read_memory (CORE_ADDR memaddr, unsigned char *myaddr,
+                                  int len)
 {
   return child_xfer_memory (memaddr, (char *) myaddr, len, 0, 0) != len;
 }
@@ -1688,30 +1351,18 @@ win32_read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
    called through write_inferior_memory, which handles breakpoint shadowing.
    Write LEN bytes from the buffer at MYADDR to MEMADDR.
    Returns 0 on success and errno on failure.  */
-static int
-win32_write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
-                            int len)
+int
+win32_process_target::write_memory (CORE_ADDR memaddr,
+                                   const unsigned char *myaddr, int len)
 {
   return child_xfer_memory (memaddr, (char *) myaddr, len, 1, 0) != len;
 }
 
 /* Send an interrupt request to the inferior process. */
-static void
-win32_request_interrupt (void)
+void
+win32_process_target::request_interrupt ()
 {
-  winapi_DebugBreakProcess DebugBreakProcess;
-  winapi_GenerateConsoleCtrlEvent GenerateConsoleCtrlEvent;
-
-#ifdef _WIN32_WCE
-  HMODULE dll = GetModuleHandle (_T("COREDLL.DLL"));
-#else
-  HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
-#endif
-
-  GenerateConsoleCtrlEvent = GETPROCADDRESS (dll, GenerateConsoleCtrlEvent);
-
-  if (GenerateConsoleCtrlEvent != NULL
-      && GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id))
+  if (GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id))
     return;
 
   /* GenerateConsoleCtrlEvent can fail if process id being debugged is
@@ -1719,80 +1370,32 @@ win32_request_interrupt (void)
      Fallback to XP/Vista 'DebugBreakProcess', which generates a
      breakpoint exception in the interior process.  */
 
-  DebugBreakProcess = GETPROCADDRESS (dll, DebugBreakProcess);
-
-  if (DebugBreakProcess != NULL
-      && DebugBreakProcess (current_process_handle))
+  if (DebugBreakProcess (current_process_handle))
     return;
 
   /* Last resort, suspend all threads manually.  */
   soft_interrupt_requested = 1;
 }
 
-#ifdef _WIN32_WCE
-int
-win32_error_to_fileio_error (DWORD err)
+bool
+win32_process_target::supports_hardware_single_step ()
 {
-  switch (err)
-    {
-    case ERROR_BAD_PATHNAME:
-    case ERROR_FILE_NOT_FOUND:
-    case ERROR_INVALID_NAME:
-    case ERROR_PATH_NOT_FOUND:
-      return FILEIO_ENOENT;
-    case ERROR_CRC:
-    case ERROR_IO_DEVICE:
-    case ERROR_OPEN_FAILED:
-      return FILEIO_EIO;
-    case ERROR_INVALID_HANDLE:
-      return FILEIO_EBADF;
-    case ERROR_ACCESS_DENIED:
-    case ERROR_SHARING_VIOLATION:
-      return FILEIO_EACCES;
-    case ERROR_NOACCESS:
-      return FILEIO_EFAULT;
-    case ERROR_BUSY:
-      return FILEIO_EBUSY;
-    case ERROR_ALREADY_EXISTS:
-    case ERROR_FILE_EXISTS:
-      return FILEIO_EEXIST;
-    case ERROR_BAD_DEVICE:
-      return FILEIO_ENODEV;
-    case ERROR_DIRECTORY:
-      return FILEIO_ENOTDIR;
-    case ERROR_FILENAME_EXCED_RANGE:
-    case ERROR_INVALID_DATA:
-    case ERROR_INVALID_PARAMETER:
-    case ERROR_NEGATIVE_SEEK:
-      return FILEIO_EINVAL;
-    case ERROR_TOO_MANY_OPEN_FILES:
-      return FILEIO_EMFILE;
-    case ERROR_HANDLE_DISK_FULL:
-    case ERROR_DISK_FULL:
-      return FILEIO_ENOSPC;
-    case ERROR_WRITE_PROTECT:
-      return FILEIO_EROFS;
-    case ERROR_NOT_SUPPORTED:
-      return FILEIO_ENOSYS;
-    }
-
-  return FILEIO_EUNKNOWN;
+  return true;
 }
 
-static void
-wince_hostio_last_error (char *buf)
+bool
+win32_process_target::supports_qxfer_siginfo ()
 {
-  DWORD winerr = GetLastError ();
-  int fileio_err = win32_error_to_fileio_error (winerr);
-  sprintf (buf, "F-1,%x", fileio_err);
+  return true;
 }
-#endif
 
 /* Write Windows signal info.  */
 
-static int
-win32_xfer_siginfo (const char *annex, unsigned char *readbuf,
-                   unsigned const char *writebuf, CORE_ADDR offset, int len)
+int
+win32_process_target::qxfer_siginfo (const char *annex,
+                                    unsigned char *readbuf,
+                                    unsigned const char *writebuf,
+                                    CORE_ADDR offset, int len)
 {
   if (siginfo_er.ExceptionCode == 0)
     return -1;
@@ -1800,24 +1403,51 @@ win32_xfer_siginfo (const char *annex, unsigned char *readbuf,
   if (readbuf == nullptr)
     return -1;
 
-  if (offset > sizeof (siginfo_er))
+  char *buf = (char *) &siginfo_er;
+  size_t bufsize = sizeof (siginfo_er);
+
+#ifdef __x86_64__
+  EXCEPTION_RECORD32 er32;
+  if (wow64_process)
+    {
+      buf = (char *) &er32;
+      bufsize = sizeof (er32);
+
+      er32.ExceptionCode = siginfo_er.ExceptionCode;
+      er32.ExceptionFlags = siginfo_er.ExceptionFlags;
+      er32.ExceptionRecord = (uintptr_t) siginfo_er.ExceptionRecord;
+      er32.ExceptionAddress = (uintptr_t) siginfo_er.ExceptionAddress;
+      er32.NumberParameters = siginfo_er.NumberParameters;
+      int i;
+      for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
+       er32.ExceptionInformation[i] = siginfo_er.ExceptionInformation[i];
+    }
+#endif
+
+  if (offset > bufsize)
     return -1;
 
-  if (offset + len > sizeof (siginfo_er))
-    len = sizeof (siginfo_er) - offset;
+  if (offset + len > bufsize)
+    len = bufsize - offset;
 
-  memcpy (readbuf, (char *) &siginfo_er + offset, len);
+  memcpy (readbuf, buf + offset, len);
 
   return len;
 }
 
+bool
+win32_process_target::supports_get_tib_address ()
+{
+  return true;
+}
+
 /* Write Windows OS Thread Information Block address.  */
 
-static int
-win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+int
+win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
 {
-  win32_thread_info *th;
-  th = thread_rec (ptid, 0);
+  windows_thread_info *th;
+  th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
   if (th == NULL)
     return 0;
   if (addr != NULL)
@@ -1827,98 +1457,49 @@ win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
 
 /* Implementation of the target_ops method "sw_breakpoint_from_kind".  */
 
-static const gdb_byte *
-win32_sw_breakpoint_from_kind (int kind, int *size)
+const gdb_byte *
+win32_process_target::sw_breakpoint_from_kind (int kind, int *size)
 {
   *size = the_low_target.breakpoint_len;
   return the_low_target.breakpoint;
 }
 
+bool
+win32_process_target::stopped_by_sw_breakpoint ()
+{
+  windows_thread_info *th = thread_rec (current_thread_ptid (),
+                                       DONT_INVALIDATE_CONTEXT);
+  return th == nullptr ? false : th->stopped_at_software_breakpoint;
+}
+
+bool
+win32_process_target::supports_stopped_by_sw_breakpoint ()
+{
+  return true;
+}
+
+CORE_ADDR
+win32_process_target::read_pc (struct regcache *regcache)
+{
+  return (*the_low_target.get_pc) (regcache);
+}
+
+void
+win32_process_target::write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  return (*the_low_target.set_pc) (regcache, pc);
+}
+
 /* The win32 target ops object.  */
 
 static win32_process_target the_win32_target;
 
-static process_stratum_target win32_target_ops = {
-  win32_resume,
-  win32_wait,
-  win32_fetch_inferior_registers,
-  win32_store_inferior_registers,
-  NULL, /* prepare_to_access_memory */
-  NULL, /* done_accessing_memory */
-  win32_read_inferior_memory,
-  win32_write_inferior_memory,
-  NULL, /* lookup_symbols */
-  win32_request_interrupt,
-  NULL, /* read_auxv */
-  win32_supports_z_point_type,
-  win32_insert_point,
-  win32_remove_point,
-  NULL, /* stopped_by_sw_breakpoint */
-  NULL, /* supports_stopped_by_sw_breakpoint */
-  NULL, /* stopped_by_hw_breakpoint */
-  NULL, /* supports_stopped_by_hw_breakpoint */
-  target_can_do_hardware_single_step,
-  win32_stopped_by_watchpoint,
-  win32_stopped_data_address,
-  NULL, /* read_offsets */
-  NULL, /* get_tls_address */
-#ifdef _WIN32_WCE
-  wince_hostio_last_error,
-#else
-  hostio_last_error_from_errno,
-#endif
-  NULL, /* qxfer_osdata */
-  win32_xfer_siginfo,
-  NULL, /* supports_non_stop */
-  NULL, /* async */
-  NULL, /* start_non_stop */
-  NULL, /* supports_multi_process */
-  NULL, /* supports_fork_events */
-  NULL, /* supports_vfork_events */
-  NULL, /* supports_exec_events */
-  NULL, /* handle_new_gdb_connection */
-  NULL, /* handle_monitor_command */
-  NULL, /* core_of_thread */
-  NULL, /* read_loadmap */
-  NULL, /* process_qsupported */
-  NULL, /* supports_tracepoints */
-  NULL, /* read_pc */
-  NULL, /* write_pc */
-  NULL, /* thread_stopped */
-  win32_get_tib_address,
-  NULL, /* pause_all */
-  NULL, /* unpause_all */
-  NULL, /* stabilize_threads */
-  NULL, /* install_fast_tracepoint_jump_pad */
-  NULL, /* emit_ops */
-  NULL, /* supports_disable_randomization */
-  NULL, /* get_min_fast_tracepoint_insn_len */
-  NULL, /* qxfer_libraries_svr4 */
-  NULL, /* support_agent */
-  NULL, /* enable_btrace */
-  NULL, /* disable_btrace */
-  NULL, /* read_btrace */
-  NULL, /* read_btrace_conf */
-  NULL, /* supports_range_stepping */
-  NULL, /* pid_to_exec_file */
-  NULL, /* multifs_open */
-  NULL, /* multifs_unlink */
-  NULL, /* multifs_readlink */
-  NULL, /* breakpoint_kind_from_pc */
-  win32_sw_breakpoint_from_kind,
-  NULL, /* thread_name */
-  NULL, /* breakpoint_kind_from_current_state */
-  NULL, /* supports_software_single_step */
-  NULL, /* supports_catch_syscall */
-  NULL, /* get_ipa_tdesc_idx */
-  NULL, /* thread_handle */
-  &the_win32_target,
-};
-
 /* Initialize the Win32 backend.  */
 void
 initialize_low (void)
 {
-  set_target_ops (&win32_target_ops);
+  set_target_ops (&the_win32_target);
   the_low_target.arch_setup ();
+
+  initialize_loadable ();
 }