Make "show remote exec-file" inferior-aware
[deliverable/binutils-gdb.git] / gdb / windows-nat.c
index 9212adfefd2fdc349e8b46bda294f193e7e2d863..36a47f7cdbc28be0e4791a9e40795580a572166f 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-vector operations for controlling windows child processes, for GDB.
 
-   Copyright (C) 1995-2014 Free Software Foundation, Inc.
+   Copyright (C) 1995-2020 Free Software Foundation, Inc.
 
    Contributed by Cygnus Solutions, A Red Hat Company.
 
@@ -24,8 +24,8 @@
 #include "defs.h"
 #include "frame.h"             /* required by inferior.h */
 #include "inferior.h"
+#include "infrun.h"
 #include "target.h"
-#include "exceptions.h"
 #include "gdbcore.h"
 #include "command.h"
 #include "completer.h"
@@ -34,7 +34,6 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <fcntl.h>
-#include <stdlib.h>
 #include <windows.h>
 #include <imagehlp.h>
 #include <psapi.h>
 #include <sys/cygwin.h>
 #include <cygwin/version.h>
 #endif
+#include <algorithm>
 
-#include "buildsym.h"
 #include "filenames.h"
 #include "symfile.h"
 #include "objfiles.h"
 #include "gdb_bfd.h"
 #include "gdb_obstack.h"
-#include <string.h>
 #include "gdbthread.h"
 #include "gdbcmd.h"
 #include <unistd.h>
 #include "solist.h"
 #include "solib.h"
 #include "xml-support.h"
+#include "inttypes.h"
 
 #include "i386-tdep.h"
 #include "i387-tdep.h"
 
 #include "windows-tdep.h"
 #include "windows-nat.h"
-#include "i386-nat.h"
+#include "x86-nat.h"
 #include "complaints.h"
+#include "inf-child.h"
+#include "gdbsupport/gdb_tilde_expand.h"
+#include "gdbsupport/pathstuff.h"
+#include "gdbsupport/gdb_wait.h"
 
 #define AdjustTokenPrivileges          dyn_AdjustTokenPrivileges
 #define DebugActiveProcessStop         dyn_DebugActiveProcessStop
 #define GetConsoleFontSize             dyn_GetConsoleFontSize
 #define GetCurrentConsoleFont          dyn_GetCurrentConsoleFont
 
-static BOOL WINAPI (*AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES,
-                                           DWORD, PTOKEN_PRIVILEGES, PDWORD);
-static BOOL WINAPI (*DebugActiveProcessStop) (DWORD);
-static BOOL WINAPI (*DebugBreakProcess) (HANDLE);
-static BOOL WINAPI (*DebugSetProcessKillOnExit) (BOOL);
-static BOOL WINAPI (*EnumProcessModules) (HANDLE, HMODULE *, DWORD,
-                                         LPDWORD);
-static BOOL WINAPI (*GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO,
-                                           DWORD);
-static BOOL WINAPI (*LookupPrivilegeValueA)(LPCSTR, LPCSTR, PLUID);
-static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE);
-static BOOL WINAPI (*GetCurrentConsoleFont) (HANDLE, BOOL,
-                                            CONSOLE_FONT_INFO *);
-static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD);
-
-static struct target_ops windows_ops;
+typedef BOOL WINAPI (AdjustTokenPrivileges_ftype) (HANDLE, BOOL,
+                                                  PTOKEN_PRIVILEGES,
+                                                  DWORD, PTOKEN_PRIVILEGES,
+                                                  PDWORD);
+static AdjustTokenPrivileges_ftype *AdjustTokenPrivileges;
+
+typedef BOOL WINAPI (DebugActiveProcessStop_ftype) (DWORD);
+static DebugActiveProcessStop_ftype *DebugActiveProcessStop;
+
+typedef BOOL WINAPI (DebugBreakProcess_ftype) (HANDLE);
+static DebugBreakProcess_ftype *DebugBreakProcess;
+
+typedef BOOL WINAPI (DebugSetProcessKillOnExit_ftype) (BOOL);
+static DebugSetProcessKillOnExit_ftype *DebugSetProcessKillOnExit;
+
+typedef BOOL WINAPI (EnumProcessModules_ftype) (HANDLE, HMODULE *, DWORD,
+                                               LPDWORD);
+static EnumProcessModules_ftype *EnumProcessModules;
+
+typedef BOOL WINAPI (GetModuleInformation_ftype) (HANDLE, HMODULE,
+                                                 LPMODULEINFO, DWORD);
+static GetModuleInformation_ftype *GetModuleInformation;
+
+typedef BOOL WINAPI (LookupPrivilegeValueA_ftype) (LPCSTR, LPCSTR, PLUID);
+static LookupPrivilegeValueA_ftype *LookupPrivilegeValueA;
+
+typedef BOOL WINAPI (OpenProcessToken_ftype) (HANDLE, DWORD, PHANDLE);
+static OpenProcessToken_ftype *OpenProcessToken;
+
+typedef BOOL WINAPI (GetCurrentConsoleFont_ftype) (HANDLE, BOOL,
+                                                  CONSOLE_FONT_INFO *);
+static GetCurrentConsoleFont_ftype *GetCurrentConsoleFont;
+
+typedef COORD WINAPI (GetConsoleFontSize_ftype) (HANDLE, DWORD);
+static GetConsoleFontSize_ftype *GetConsoleFontSize;
 
 #undef STARTUPINFO
 #undef CreateProcess
@@ -101,7 +123,8 @@ static struct target_ops windows_ops;
 
 #ifndef __CYGWIN__
 # define __PMAX        (MAX_PATH + 1)
-  static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, LPSTR, DWORD);
+  typedef DWORD WINAPI (GetModuleFileNameEx_ftype) (HANDLE, HMODULE, LPSTR, DWORD);
+  static GetModuleFileNameEx_ftype *GetModuleFileNameEx;
 # define STARTUPINFO STARTUPINFOA
 # define CreateProcess CreateProcessA
 # define GetModuleFileNameEx_name "GetModuleFileNameExA"
@@ -113,8 +136,9 @@ static struct target_ops windows_ops;
   static CORE_ADDR cygwin_load_end;
 #   define __USEWIDE
     typedef wchar_t cygwin_buf_t;
-    static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE,
-                                               LPWSTR, DWORD);
+    typedef DWORD WINAPI (GetModuleFileNameEx_ftype) (HANDLE, HMODULE,
+                                                     LPWSTR, DWORD);
+    static GetModuleFileNameEx_ftype *GetModuleFileNameEx;
 #   define STARTUPINFO STARTUPINFOW
 #   define CreateProcess CreateProcessW
 #   define GetModuleFileNameEx_name "GetModuleFileNameExW"
@@ -123,8 +147,10 @@ static struct target_ops windows_ops;
 
 static int have_saved_context; /* True if we've saved context from a
                                   cygwin signal.  */
-static CONTEXT saved_context;  /* Containes the saved context from a
+#ifdef __CYGWIN__
+static CONTEXT saved_context;  /* Contains the saved context from a
                                   cygwin signal.  */
+#endif
 
 /* If we're not using the old Cygwin header file set, define the
    following which never should have been in the generic Win32 API
@@ -133,7 +159,6 @@ static CONTEXT saved_context;       /* Containes the saved context from a
 enum
   {
     FLAG_TRACE_BIT = 0x100,
-    CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
   };
 #endif
 
@@ -143,8 +168,9 @@ enum
 #define CONTEXT_EXTENDED_REGISTERS 0
 #endif
 
-#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
-       | CONTEXT_EXTENDED_REGISTERS
+#define CONTEXT_DEBUGGER_DR CONTEXT_FULL | CONTEXT_FLOATING_POINT \
+        | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS \
+        | CONTEXT_EXTENDED_REGISTERS
 
 static uintptr_t dr[8];
 static int debug_registers_changed;
@@ -153,6 +179,19 @@ static int debug_registers_used;
 static int windows_initialization_done;
 #define DR6_CLEAR_VALUE 0xffff0ff0
 
+/* The exception thrown by a program to tell the debugger the name of
+   a thread.  The exception record contains an ID of a thread and a
+   name to give it.  This exception has no documented name, but MSDN
+   dubs it "MS_VC_EXCEPTION" in one code example.  */
+#define MS_VC_EXCEPTION 0x406d1388
+
+typedef enum
+{
+  HANDLE_EXCEPTION_UNHANDLED = 0,
+  HANDLE_EXCEPTION_HANDLED,
+  HANDLE_EXCEPTION_IGNORED
+} handle_exception_result;
+
 /* The string sent by cygwin when it processes a signal.
    FIXME: This should be in a cygwin include file.  */
 #ifndef _CYGWIN_SIGNAL_STRING
@@ -165,10 +204,6 @@ static int windows_initialization_done;
 #define DEBUG_MEM(x)   if (debug_memory)       printf_unfiltered x
 #define DEBUG_EXCEPT(x)        if (debug_exceptions)   printf_unfiltered x
 
-static void windows_stop (ptid_t);
-static int windows_thread_alive (struct target_ops *, ptid_t);
-static void windows_kill_inferior (struct target_ops *);
-
 static void cygwin_set_dr (int i, CORE_ADDR addr);
 static void cygwin_set_dr7 (unsigned long val);
 static CORE_ADDR cygwin_get_dr (int i);
@@ -180,9 +215,9 @@ static enum gdb_signal last_sig = GDB_SIGNAL_0;
 
 /* Thread information structure used to track information that is
    not available in gdb's thread structure.  */
-typedef struct thread_info_struct
+typedef struct windows_thread_info_struct
   {
-    struct thread_info_struct *next;
+    struct windows_thread_info_struct *next;
     DWORD id;
     HANDLE h;
     CORE_ADDR thread_local_base;
@@ -190,19 +225,17 @@ typedef struct thread_info_struct
     int suspended;
     int reload_context;
     CONTEXT context;
-    STACKFRAME sf;
   }
-thread_info;
+windows_thread_info;
 
-static thread_info thread_head;
+static windows_thread_info thread_head;
 
 /* The process and thread handles for the above context.  */
 
 static DEBUG_EVENT current_event;      /* The current debug event from
                                           WaitForDebugEvent */
 static HANDLE current_process_handle;  /* Currently executing process */
-static thread_info *current_thread;    /* Info on currently selected thread */
-static DWORD main_thread_id;           /* Thread ID of the main thread */
+static windows_thread_info *current_thread;    /* Info on currently selected thread */
 
 /* Counts of things.  */
 static int exception_count = 0;
@@ -211,16 +244,16 @@ static int saw_create;
 static int open_process_used = 0;
 
 /* User options.  */
-static int new_console = 0;
+static bool new_console = false;
 #ifdef __CYGWIN__
-static int cygwin_exceptions = 0;
+static bool cygwin_exceptions = false;
 #endif
-static int new_group = 1;
-static int debug_exec = 0;             /* show execution */
-static int debug_events = 0;           /* show events from kernel */
-static int debug_memory = 0;           /* show target memory accesses */
-static int debug_exceptions = 0;       /* show target exceptions */
-static int useshell = 0;               /* use shell for subprocesses */
+static bool new_group = true;
+static bool debug_exec = false;                /* show execution */
+static bool debug_events = false;      /* show events from kernel */
+static bool debug_memory = false;      /* show target memory accesses */
+static bool debug_exceptions = false;  /* show target exceptions */
+static bool useshell = false;          /* use shell for subprocesses */
 
 /* This vector maps GDB's idea of a register's number into an offset
    in the windows exception context vector.
@@ -246,25 +279,80 @@ static const int *mappings;
    a segment register or not.  */
 static segment_register_p_ftype *segment_register_p;
 
+/* See windows_nat_target::resume to understand why this is commented
+   out.  */
+#if 0
 /* This vector maps the target's idea of an exception (extracted
    from the DEBUG_EVENT structure) to GDB's idea.  */
 
 struct xlate_exception
   {
-    int them;
+    DWORD them;
     enum gdb_signal us;
   };
 
-static const struct xlate_exception
-  xlate[] =
+static const struct xlate_exception xlate[] =
 {
   {EXCEPTION_ACCESS_VIOLATION, GDB_SIGNAL_SEGV},
   {STATUS_STACK_OVERFLOW, GDB_SIGNAL_SEGV},
   {EXCEPTION_BREAKPOINT, GDB_SIGNAL_TRAP},
   {DBG_CONTROL_C, GDB_SIGNAL_INT},
   {EXCEPTION_SINGLE_STEP, GDB_SIGNAL_TRAP},
-  {STATUS_FLOAT_DIVIDE_BY_ZERO, GDB_SIGNAL_FPE},
-  {-1, -1}};
+  {STATUS_FLOAT_DIVIDE_BY_ZERO, GDB_SIGNAL_FPE}
+};
+
+#endif /* 0 */
+
+struct windows_nat_target final : public x86_nat_target<inf_child_target>
+{
+  void close () override;
+
+  void attach (const char *, int) override;
+
+  bool attach_no_wait () override
+  { return true; }
+
+  void detach (inferior *, int) override;
+
+  void resume (ptid_t, int , enum gdb_signal) override;
+
+  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+
+  enum target_xfer_status xfer_partial (enum target_object object,
+                                       const char *annex,
+                                       gdb_byte *readbuf,
+                                       const gdb_byte *writebuf,
+                                       ULONGEST offset, ULONGEST len,
+                                       ULONGEST *xfered_len) override;
+
+  void files_info () override;
+
+  void kill () override;
+
+  void create_inferior (const char *, const std::string &,
+                       char **, int) override;
+
+  void mourn_inferior () override;
+
+  bool thread_alive (ptid_t ptid) override;
+
+  std::string pid_to_str (ptid_t) override;
+
+  void interrupt () override;
+
+  char *pid_to_exec_file (int pid) override;
+
+  ptid_t get_ada_task_ptid (long lwp, long thread) override;
+
+  bool get_tib_address (ptid_t ptid, CORE_ADDR *addr) override;
+
+  const char *thread_name (struct thread_info *) override;
+};
+
+static windows_nat_target the_windows_nat_target;
 
 /* Set the MAPPINGS static global to OFFSETS.
    See the description of MAPPINGS for more details.  */
@@ -294,10 +382,10 @@ check (BOOL ok, const char *file, int line)
 /* Find a thread record given a thread id.  If GET_CONTEXT is not 0,
    then also retrieve the context for this thread.  If GET_CONTEXT is
    negative, then don't suspend the thread.  */
-static thread_info *
+static windows_thread_info *
 thread_rec (DWORD id, int get_context)
 {
-  thread_info *th;
+  windows_thread_info *th;
 
   for (th = &thread_head; (th = th->next) != NULL;)
     if (th->id == id)
@@ -310,12 +398,21 @@ thread_rec (DWORD id, int get_context)
                  {
                    DWORD err = GetLastError ();
 
-                   warning (_("SuspendThread (tid=0x%x) failed."
-                              " (winerr %u)"),
-                            (unsigned) id, (unsigned) err);
-                   return NULL;
+                   /* We get Access Denied (5) when trying to suspend
+                      threads that Windows started on behalf of the
+                      debuggee, usually when those threads are just
+                      about to exit.
+                      We can get Invalid Handle (6) if the main thread
+                      has exited.  */
+                   if (err != ERROR_INVALID_HANDLE
+                       && err != ERROR_ACCESS_DENIED)
+                     warning (_("SuspendThread (tid=0x%x) failed."
+                                " (winerr %u)"),
+                              (unsigned) id, (unsigned) err);
+                   th->suspended = -1;
                  }
-               th->suspended = 1;
+               else
+                 th->suspended = 1;
              }
            else if (get_context < 0)
              th->suspended = -1;
@@ -327,27 +424,44 @@ thread_rec (DWORD id, int get_context)
   return NULL;
 }
 
-/* Add a thread to the thread list.  */
-static thread_info *
-windows_add_thread (ptid_t ptid, HANDLE h, void *tlb)
+/* Add a thread to the thread list.
+
+   PTID is the ptid of the thread to be added.
+   H is its Windows handle.
+   TLB is its thread local base.
+   MAIN_THREAD_P should be true if the thread to be added is
+   the main thread, false otherwise.  */
+
+static windows_thread_info *
+windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p)
 {
-  thread_info *th;
+  windows_thread_info *th;
   DWORD id;
 
-  gdb_assert (ptid_get_tid (ptid) != 0);
+  gdb_assert (ptid.tid () != 0);
 
-  id = ptid_get_tid (ptid);
+  id = ptid.tid ();
 
   if ((th = thread_rec (id, FALSE)))
     return th;
 
-  th = XCNEW (thread_info);
+  th = XCNEW (windows_thread_info);
   th->id = id;
   th->h = h;
   th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
   th->next = thread_head.next;
   thread_head.next = th;
-  add_thread (ptid);
+
+  /* Add this new thread to the list of threads.
+
+     To be consistent with what's done on other platforms, we add
+     the main thread silently (in reality, this thread is really
+     more of a process to the user than a thread).  */
+  if (main_thread_p)
+    add_thread_silent (ptid);
+  else
+    add_thread (ptid);
+
   /* Set the debug registers for the new thread if they are used.  */
   if (debug_registers_used)
     {
@@ -366,41 +480,56 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb)
   return th;
 }
 
-/* Clear out any old thread list and reintialize it to a
+/* Clear out any old thread list and reinitialize it to a
    pristine state.  */
 static void
 windows_init_thread_list (void)
 {
-  thread_info *th = &thread_head;
+  windows_thread_info *th = &thread_head;
 
   DEBUG_EVENTS (("gdb: windows_init_thread_list\n"));
   init_thread_list ();
   while (th->next != NULL)
     {
-      thread_info *here = th->next;
+      windows_thread_info *here = th->next;
       th->next = here->next;
       xfree (here);
     }
   thread_head.next = NULL;
 }
 
-/* Delete a thread from the list of threads.  */
+/* Delete a thread from the list of threads.
+
+   PTID is the ptid of the thread to be deleted.
+   EXIT_CODE is the thread's exit code.
+   MAIN_THREAD_P should be true if the thread to be deleted is
+   the main thread, false otherwise.  */
+
 static void
-windows_delete_thread (ptid_t ptid, DWORD exit_code)
+windows_delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p)
 {
-  thread_info *th;
+  windows_thread_info *th;
   DWORD id;
 
-  gdb_assert (ptid_get_tid (ptid) != 0);
+  gdb_assert (ptid.tid () != 0);
+
+  id = ptid.tid ();
+
+  /* Emit a notification about the thread being deleted.
 
-  id = ptid_get_tid (ptid);
+     Note that no notification was printed when the main thread
+     was created, and thus, unless in verbose mode, we should be
+     symmetrical, and avoid that notification for the main thread
+     here as well.  */
 
   if (info_verbose)
-    printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid));
-  else if (print_thread_events && id != main_thread_id)
+    printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid).c_str ());
+  else if (print_thread_events && !main_thread_p)
     printf_unfiltered (_("[%s exited with code %u]\n"),
-                      target_pid_to_str (ptid), (unsigned) exit_code);
-  delete_thread (ptid);
+                      target_pid_to_str (ptid).c_str (),
+                      (unsigned) exit_code);
+
+  delete_thread (find_thread_ptid (ptid));
 
   for (th = &thread_head;
        th->next != NULL && th->next->id != id;
@@ -409,43 +538,85 @@ windows_delete_thread (ptid_t ptid, DWORD exit_code)
 
   if (th->next != NULL)
     {
-      thread_info *here = th->next;
+      windows_thread_info *here = th->next;
       th->next = here->next;
+      xfree (here->name);
       xfree (here);
     }
 }
 
+/* Fetches register number R from the given windows_thread_info,
+   and supplies its value to the given regcache.
+
+   This function assumes that R is non-negative.  A failed assertion
+   is raised if that is not true.
+
+   This function assumes that TH->RELOAD_CONTEXT is not set, meaning
+   that the windows_thread_info has an up-to-date context.  A failed
+   assertion is raised if that assumption is violated.  */
+
 static void
-do_windows_fetch_inferior_registers (struct regcache *regcache, int r)
+windows_fetch_one_register (struct regcache *regcache,
+                           windows_thread_info *th, int r)
 {
-  char *context_offset = ((char *) &current_thread->context) + mappings[r];
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  gdb_assert (r >= 0);
+  gdb_assert (!th->reload_context);
+
+  char *context_offset = ((char *) &th->context) + mappings[r];
+  struct gdbarch *gdbarch = regcache->arch ();
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  long l;
 
-  if (!current_thread)
-    return;    /* Windows sometimes uses a non-existent thread id in its
-                  events.  */
+  if (r == I387_FISEG_REGNUM (tdep))
+    {
+      long l = *((long *) context_offset) & 0xffff;
+      regcache->raw_supply (r, (char *) &l);
+    }
+  else if (r == I387_FOP_REGNUM (tdep))
+    {
+      long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
+      regcache->raw_supply (r, (char *) &l);
+    }
+  else if (segment_register_p (r))
+    {
+      /* GDB treats segment registers as 32bit registers, but they are
+        in fact only 16 bits long.  Make sure we do not read extra
+        bits from our source buffer.  */
+      long l = *((long *) context_offset) & 0xffff;
+      regcache->raw_supply (r, (char *) &l);
+    }
+  else
+    regcache->raw_supply (r, context_offset);
+}
+
+void
+windows_nat_target::fetch_registers (struct regcache *regcache, int r)
+{
+  DWORD tid = regcache->ptid ().tid ();
+  windows_thread_info *th = thread_rec (tid, TRUE);
 
-  if (current_thread->reload_context)
+  /* Check if TH exists.  Windows sometimes uses a non-existent
+     thread id in its events.  */
+  if (th == NULL)
+    return;
+
+  if (th->reload_context)
     {
-#ifdef __COPY_CONTEXT_SIZE
+#ifdef __CYGWIN__
       if (have_saved_context)
        {
          /* Lie about where the program actually is stopped since
             cygwin has informed us that we should consider the signal
             to have occurred at another location which is stored in
             "saved_context.  */
-         memcpy (&current_thread->context, &saved_context,
+         memcpy (&th->context, &saved_context,
                  __COPY_CONTEXT_SIZE);
          have_saved_context = 0;
        }
       else
 #endif
        {
-         thread_info *th = current_thread;
          th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
-         GetThreadContext (th->h, &th->context);
+         CHECK (GetThreadContext (th->h, &th->context));
          /* Copy dr values from that thread.
             But only if there were not modified since last stop.
             PR gdb/2388 */
@@ -459,223 +630,60 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r)
              dr[7] = th->context.Dr7;
            }
        }
-      current_thread->reload_context = 0;
+      th->reload_context = 0;
     }
 
-  if (r == I387_FISEG_REGNUM (tdep))
-    {
-      l = *((long *) context_offset) & 0xffff;
-      regcache_raw_supply (regcache, r, (char *) &l);
-    }
-  else if (r == I387_FOP_REGNUM (tdep))
-    {
-      l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
-      regcache_raw_supply (regcache, r, (char *) &l);
-    }
-  else if (segment_register_p (r))
-    {
-      /* GDB treats segment registers as 32bit registers, but they are
-        in fact only 16 bits long.  Make sure we do not read extra
-        bits from our source buffer.  */
-      l = *((long *) context_offset) & 0xffff;
-      regcache_raw_supply (regcache, r, (char *) &l);
-    }
-  else if (r >= 0)
-    regcache_raw_supply (regcache, r, context_offset);
+  if (r < 0)
+    for (r = 0; r < gdbarch_num_regs (regcache->arch()); r++)
+      windows_fetch_one_register (regcache, th, r);
   else
-    {
-      for (r = 0; r < gdbarch_num_regs (gdbarch); r++)
-       do_windows_fetch_inferior_registers (regcache, r);
-    }
+    windows_fetch_one_register (regcache, th, r);
 }
 
-static void
-windows_fetch_inferior_registers (struct target_ops *ops,
-                                 struct regcache *regcache, int r)
-{
-  current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE);
-  /* Check if current_thread exists.  Windows sometimes uses a non-existent
-     thread id in its events.  */
-  if (current_thread)
-    do_windows_fetch_inferior_registers (regcache, r);
-}
+/* Collect the register number R from the given regcache, and store
+   its value into the corresponding area of the given thread's context.
 
-static void
-do_windows_store_inferior_registers (const struct regcache *regcache, int r)
-{
-  if (!current_thread)
-    /* Windows sometimes uses a non-existent thread id in its events.  */;
-  else if (r >= 0)
-    regcache_raw_collect (regcache, r,
-                         ((char *) &current_thread->context) + mappings[r]);
-  else
-    {
-      for (r = 0; r < gdbarch_num_regs (get_regcache_arch (regcache)); r++)
-       do_windows_store_inferior_registers (regcache, r);
-    }
-}
+   This function assumes that R is non-negative.  A failed assertion
+   assertion is raised if that is not true.  */
 
-/* Store a new register value into the current thread context.  */
 static void
-windows_store_inferior_registers (struct target_ops *ops,
-                                 struct regcache *regcache, int r)
-{
-  current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE);
-  /* Check if current_thread exists.  Windows sometimes uses a non-existent
-     thread id in its events.  */
-  if (current_thread)
-    do_windows_store_inferior_registers (regcache, r);
-}
-
-/* Get the name of a given module at given base address.  If base_address
-   is zero return the first loaded module (which is always the name of the
-   executable).  */
-static int
-get_module_name (LPVOID base_address, char *dll_name_ret)
+windows_store_one_register (const struct regcache *regcache,
+                           windows_thread_info *th, int r)
 {
-  DWORD len;
-  MODULEINFO mi;
-  int i;
-  HMODULE dh_buf[1];
-  HMODULE *DllHandle = dh_buf; /* Set to temporary storage for
-                                  initial query.  */
-  DWORD cbNeeded;
-#ifdef __CYGWIN__
-  cygwin_buf_t pathbuf[__PMAX];        /* Temporary storage prior to converting to
-                                  posix form.  __PMAX is always enough
-                                  as long as SO_NAME_MAX_PATH_SIZE is defined
-                                  as 512.  */
-#endif
+  gdb_assert (r >= 0);
 
-  cbNeeded = 0;
-  /* Find size of buffer needed to handle list of modules loaded in
-     inferior.  */
-  if (!EnumProcessModules (current_process_handle, DllHandle,
-                          sizeof (HMODULE), &cbNeeded) || !cbNeeded)
-    goto failed;
-
-  /* Allocate correct amount of space for module list.  */
-  DllHandle = (HMODULE *) alloca (cbNeeded);
-  if (!DllHandle)
-    goto failed;
+  regcache->raw_collect (r, ((char *) &th->context) + mappings[r]);
+}
 
-  /* Get the list of modules.  */
-  if (!EnumProcessModules (current_process_handle, DllHandle, cbNeeded,
-                                &cbNeeded))
-    goto failed;
+/* Store a new register value into the context of the thread tied to
+   REGCACHE.  */
 
-  for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++)
-    {
-      /* Get information on this module.  */
-      if (!GetModuleInformation (current_process_handle, DllHandle[i],
-                                &mi, sizeof (mi)))
-       error (_("Can't get module info"));
+void
+windows_nat_target::store_registers (struct regcache *regcache, int r)
+{
+  DWORD tid = regcache->ptid ().tid ();
+  windows_thread_info *th = thread_rec (tid, TRUE);
 
-      if (!base_address || mi.lpBaseOfDll == base_address)
-       {
-         /* Try to find the name of the given module.  */
-#ifdef __CYGWIN__
-         /* Cygwin prefers that the path be in /x/y/z format.  */
-         len = GetModuleFileNameEx (current_process_handle,
-                                     DllHandle[i], pathbuf, __PMAX);
-         if (len == 0)
-           error (_("Error getting dll name: %u."),
-                  (unsigned) GetLastError ());
-         if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, dll_name_ret,
-                               __PMAX) < 0)
-           error (_("Error converting dll name to POSIX: %d."), errno);
-#else
-         len = GetModuleFileNameEx (current_process_handle,
-                                     DllHandle[i], dll_name_ret, __PMAX);
-         if (len == 0)
-           error (_("Error getting dll name: %u."),
-                  (unsigned) GetLastError ());
-#endif
-         return 1;     /* success */
-       }
-    }
+  /* Check if TH exists.  Windows sometimes uses a non-existent
+     thread id in its events.  */
+  if (th == NULL)
+    return;
 
-failed:
-  dll_name_ret[0] = '\0';
-  return 0;            /* failure */
+  if (r < 0)
+    for (r = 0; r < gdbarch_num_regs (regcache->arch ()); r++)
+      windows_store_one_register (regcache, th, r);
+  else
+    windows_store_one_register (regcache, th, r);
 }
 
-/* Encapsulate the information required in a call to
-   symbol_file_add_args.  */
-struct safe_symbol_file_add_args
-{
-  char *name;
-  int from_tty;
-  struct section_addr_info *addrs;
-  int mainline;
-  int flags;
-  struct ui_file *err, *out;
-  struct objfile *ret;
-};
-
 /* Maintain a linked list of "so" information.  */
-struct lm_info
+struct lm_info_windows : public lm_info_base
 {
-  LPVOID load_addr;
+  LPVOID load_addr = 0;
 };
 
 static struct so_list solib_start, *solib_end;
 
-/* Call symbol_file_add with stderr redirected.  We don't care if there
-   are errors.  */
-static int
-safe_symbol_file_add_stub (void *argv)
-{
-#define p ((struct safe_symbol_file_add_args *) argv)
-  const int add_flags = ((p->from_tty ? SYMFILE_VERBOSE : 0)
-                         | (p->mainline ? SYMFILE_MAINLINE : 0));
-  p->ret = symbol_file_add (p->name, add_flags, p->addrs, p->flags);
-  return !!p->ret;
-#undef p
-}
-
-/* Restore gdb's stderr after calling symbol_file_add.  */
-static void
-safe_symbol_file_add_cleanup (void *p)
-{
-#define sp ((struct safe_symbol_file_add_args *)p)
-  gdb_flush (gdb_stderr);
-  gdb_flush (gdb_stdout);
-  ui_file_delete (gdb_stderr);
-  ui_file_delete (gdb_stdout);
-  gdb_stderr = sp->err;
-  gdb_stdout = sp->out;
-#undef sp
-}
-
-/* symbol_file_add wrapper that prevents errors from being displayed.  */
-static struct objfile *
-safe_symbol_file_add (char *name, int from_tty,
-                     struct section_addr_info *addrs,
-                     int mainline, int flags)
-{
-  struct safe_symbol_file_add_args p;
-  struct cleanup *cleanup;
-
-  cleanup = make_cleanup (safe_symbol_file_add_cleanup, &p);
-
-  p.err = gdb_stderr;
-  p.out = gdb_stdout;
-  gdb_flush (gdb_stderr);
-  gdb_flush (gdb_stdout);
-  gdb_stderr = ui_file_new ();
-  gdb_stdout = ui_file_new ();
-  p.name = name;
-  p.from_tty = from_tty;
-  p.addrs = addrs;
-  p.mainline = mainline;
-  p.flags = flags;
-  catch_errors (safe_symbol_file_add_stub, &p, "", RETURN_MASK_ERROR);
-
-  do_cleanups (cleanup);
-  return p.ret;
-}
-
 static struct so_list *
 windows_make_so (const char *name, LPVOID load_addr)
 {
@@ -729,8 +737,9 @@ windows_make_so (const char *name, LPVOID load_addr)
     }
 #endif
   so = XCNEW (struct so_list);
-  so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info));
-  so->lm_info->load_addr = load_addr;
+  lm_info_windows *li = new lm_info_windows;
+  so->lm_info = li;
+  li->load_addr = load_addr;
   strcpy (so->so_original_name, name);
 #ifndef __CYGWIN__
   strcpy (so->so_name, buf);
@@ -753,32 +762,25 @@ windows_make_so (const char *name, LPVOID load_addr)
   p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
   if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0)
     {
-      bfd *abfd;
       asection *text = NULL;
-      CORE_ADDR text_vma;
 
-      abfd = gdb_bfd_open (so->so_name, "pei-i386", -1);
+      gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386", -1));
 
-      if (!abfd)
+      if (abfd == NULL)
        return so;
 
-      if (bfd_check_format (abfd, bfd_object))
-       text = bfd_get_section_by_name (abfd, ".text");
+      if (bfd_check_format (abfd.get (), bfd_object))
+       text = bfd_get_section_by_name (abfd.get (), ".text");
 
       if (!text)
-       {
-         gdb_bfd_unref (abfd);
-         return so;
-       }
+       return so;
 
       /* The symbols in a dll are offset by 0x1000, which is the
         offset from 0 of the first byte in an image - because of the
         file header and the section alignment.  */
       cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *)
                                                   load_addr + 0x1000);
-      cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
-
-      gdb_bfd_unref (abfd);
+      cygwin_load_end = cygwin_load_start + bfd_section_size (text);
     }
 #endif
 
@@ -835,84 +837,78 @@ get_image_name (HANDLE h, void *address, int unicode)
   return buf;
 }
 
-/* Wait for child to do something.  Return pid of child, or -1 in case
-   of error; store status through argument pointer OURSTATUS.  */
-static int
-handle_load_dll (void *dummy)
-{
-  LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
-  char dll_buf[__PMAX];
-  char *dll_name = NULL;
-
-  dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+/* Handle a DLL load event, and return 1.
 
-  /* Try getting the DLL name by searching the list of known modules
-     and matching their base address against this new DLL's base address.
+   This function assumes that this event did not occur during inferior
+   initialization, where their event info may be incomplete (see
+   do_initial_windows_stuff and windows_add_all_dlls for more info
+   on how we handle DLL loading during that phase).  */
 
-     FIXME: brobecker/2013-12-10:
-     It seems odd to be going through this search if the DLL name could
-     simply be extracted via "event->lpImageName".  Moreover, some
-     experimentation with various versions of Windows seem to indicate
-     that it might still be too early for this DLL to be listed when
-     querying the system about the current list of modules, thus making
-     this attempt pointless.
-
-     This code can therefore probably be removed.  But at the time of
-     this writing, we are too close to creating the GDB 7.7 branch
-     for us to make such a change.  We are therefore defering it.  */
-
-  if (!get_module_name (event->lpBaseOfDll, dll_buf))
-    dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
-
-  dll_name = dll_buf;
+static void
+handle_load_dll ()
+{
+  LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
+  char *dll_name;
 
   /* Try getting the DLL name via the lpImageName field of the event.
      Note that Microsoft documents this fields as strictly optional,
      in the sense that it might be NULL.  And the first DLL event in
      particular is explicitly documented as "likely not pass[ed]"
      (source: MSDN LOAD_DLL_DEBUG_INFO structure).  */
-  if (*dll_name == '\0')
-    dll_name = get_image_name (current_process_handle,
-                              event->lpImageName, event->fUnicode);
+  dll_name = get_image_name (current_process_handle,
+                            event->lpImageName, event->fUnicode);
   if (!dll_name)
-    return 1;
+    return;
 
   solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll);
   solib_end = solib_end->next;
 
-  DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name,
-                host_address_to_string (solib_end->lm_info->load_addr)));
+  lm_info_windows *li = (lm_info_windows *) solib_end->lm_info;
 
-  return 1;
+  DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name,
+                host_address_to_string (li->load_addr)));
 }
 
 static void
 windows_free_so (struct so_list *so)
 {
-  if (so->lm_info)
-    xfree (so->lm_info);
+  lm_info_windows *li = (lm_info_windows *) so->lm_info;
+
+  delete li;
   xfree (so);
 }
 
-static int
-handle_unload_dll (void *dummy)
+/* Handle a DLL unload event.
+   Return 1 if successful, or zero otherwise.
+
+   This function assumes that this event did not occur during inferior
+   initialization, where their event info may be incomplete (see
+   do_initial_windows_stuff and windows_add_all_dlls for more info
+   on how we handle DLL loading during that phase).  */
+
+static void
+handle_unload_dll ()
 {
   LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll;
   struct so_list *so;
 
   for (so = &solib_start; so->next != NULL; so = so->next)
-    if (so->next->lm_info->load_addr == lpBaseOfDll)
-      {
-       struct so_list *sodel = so->next;
+    {
+      lm_info_windows *li_next = (lm_info_windows *) so->next->lm_info;
 
-       so->next = sodel->next;
-       if (!so->next)
-         solib_end = so;
-       DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+      if (li_next->load_addr == lpBaseOfDll)
+       {
+         struct so_list *sodel = so->next;
 
-       windows_free_so (sodel);
-       return 1;
-      }
+         so->next = sodel->next;
+         if (!so->next)
+           solib_end = so;
+         DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+
+         windows_free_so (sodel);
+         return;
+       }
+    }
 
   /* We did not find any DLL that was previously loaded at this address,
      so register a complaint.  We do not report an error, because we have
@@ -921,40 +917,58 @@ handle_unload_dll (void *dummy)
      4 mysterious UNLOAD_DLL_DEBUG_EVENTs during the startup phase (these
      events are apparently caused by the WOW layer, the interface between
      32bit and 64bit worlds).  */
-  complaint (&symfile_complaints, _("dll starting at %s not found."),
+  complaint (_("dll starting at %s not found."),
             host_address_to_string (lpBaseOfDll));
+}
 
-  return 0;
+/* Call FUNC wrapped in a TRY/CATCH that swallows all GDB
+   exceptions.  */
+
+static void
+catch_errors (void (*func) ())
+{
+  try
+    {
+      func ();
+    }
+  catch (const gdb_exception &ex)
+    {
+      exception_print (gdb_stderr, ex);
+    }
 }
 
 /* Clear list of loaded DLLs.  */
 static void
 windows_clear_solib (void)
 {
-  solib_start.next = NULL;
+  struct so_list *so;
+
+  for (so = solib_start.next; so; so = solib_start.next)
+    {
+      solib_start.next = so->next;
+      windows_free_so (so);
+    }
+
   solib_end = &solib_start;
 }
 
-/* Load DLL symbol info.  */
 static void
-dll_symbol_command (char *args, int from_tty)
+signal_event_command (const char *args, int from_tty)
 {
-  int n;
-  dont_repeat ();
+  uintptr_t event_id = 0;
+  char *endargs = NULL;
 
   if (args == NULL)
-    error (_("dll-symbols requires a file name"));
+    error (_("signal-event requires an argument (integer event id)"));
 
-  n = strlen (args);
-  if (n > 4 && strcasecmp (args + n - 4, ".dll") != 0)
-    {
-      char *newargs = (char *) alloca (n + 4 + 1);
-      strcpy (newargs, args);
-      strcat (newargs, ".dll");
-      args = newargs;
-    }
+  event_id = strtoumax (args, &endargs, 10);
 
-  safe_symbol_file_add (args, from_tty, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
+  if ((errno == ERANGE) || (event_id == 0) || (event_id > UINTPTR_MAX) ||
+      ((HANDLE) event_id == INVALID_HANDLE_VALUE))
+    error (_("Failed to convert `%s' to event id"), args);
+
+  SetEvent ((HANDLE) event_id);
+  CloseHandle ((HANDLE) event_id);
 }
 
 /* Handle DEBUG_STRING output from child process.
@@ -963,23 +977,28 @@ dll_symbol_command (char *args, int from_tty)
 static int
 handle_output_debug_string (struct target_waitstatus *ourstatus)
 {
-  char *s = NULL;
+  gdb::unique_xmalloc_ptr<char> s;
   int retval = 0;
 
   if (!target_read_string
        ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData,
-       &s, 1024, 0)
-      || !s || !*s)
+        &s, 1024, 0)
+      || !s || !*(s.get ()))
     /* nothing to do */;
-  else if (strncmp (s, _CYGWIN_SIGNAL_STRING,
-                   sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
+  else if (!startswith (s.get (), _CYGWIN_SIGNAL_STRING))
     {
 #ifdef __CYGWIN__
-      if (strncmp (s, "cYg", 3) != 0)
+      if (!startswith (s.get (), "cYg"))
 #endif
-       warning (("%s"), s);
+       {
+         char *p = strchr (s.get (), '\0');
+
+         if (p > s.get () && *--p == '\n')
+           *p = '\0';
+         warning (("%s"), s.get ());
+       }
     }
-#ifdef __COPY_CONTEXT_SIZE
+#ifdef __CYGWIN__
   else
     {
       /* Got a cygwin signal marker.  A cygwin signal is followed by
@@ -990,8 +1009,8 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
         to be stored at the given address in the inferior.  Tell gdb
         to treat this like a real signal.  */
       char *p;
-      int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
-      int gotasig = gdb_signal_from_host (sig);
+      int sig = strtol (s.get () + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
+      gdb_signal gotasig = gdb_signal_from_host (sig);
 
       ourstatus->value.sig = gotasig;
       if (gotasig)
@@ -1002,20 +1021,17 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
          ourstatus->kind = TARGET_WAITKIND_STOPPED;
          retval = strtoul (p, &p, 0);
          if (!retval)
-           retval = main_thread_id;
+           retval = current_event.dwThreadId;
          else if ((x = (LPCVOID) (uintptr_t) strtoull (p, NULL, 0))
                   && ReadProcessMemory (current_process_handle, x,
                                         &saved_context,
                                         __COPY_CONTEXT_SIZE, &n)
                   && n == __COPY_CONTEXT_SIZE)
            have_saved_context = 1;
-         current_event.dwThreadId = retval;
        }
     }
 #endif
 
-  if (s)
-    xfree (s);
   return retval;
 }
 
@@ -1070,14 +1086,16 @@ display_selector (HANDLE thread, DWORD sel)
          puts_filtered ("Code (Exec/Read, Conf");
          break;
        default:
-         printf_filtered ("Unknown type 0x%x",info.HighWord.Bits.Type);
+         printf_filtered ("Unknown type 0x%lx",
+                          (unsigned long) info.HighWord.Bits.Type);
        }
       if ((info.HighWord.Bits.Type & 0x1) == 0)
        puts_filtered(", N.Acc");
       puts_filtered (")\n");
       if ((info.HighWord.Bits.Type & 0x10) == 0)
        puts_filtered("System selector ");
-      printf_filtered ("Priviledge level = %d. ", info.HighWord.Bits.Dpl);
+      printf_filtered ("Priviledge level = %ld. ",
+                      (unsigned long) info.HighWord.Bits.Dpl);
       if (info.HighWord.Bits.Granularity)
        puts_filtered ("Page granular.\n");
       else
@@ -1096,7 +1114,7 @@ display_selector (HANDLE thread, DWORD sel)
 }
 
 static void
-display_selectors (char * args, int from_tty)
+display_selectors (const char * args, int from_tty)
 {
   if (!current_thread)
     {
@@ -1139,16 +1157,17 @@ display_selectors (char * args, int from_tty)
     host_address_to_string (\
       current_event.u.Exception.ExceptionRecord.ExceptionAddress))
 
-static int
+static handle_exception_result
 handle_exception (struct target_waitstatus *ourstatus)
 {
-  thread_info *th;
-  DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
+  EXCEPTION_RECORD *rec = &current_event.u.Exception.ExceptionRecord;
+  DWORD code = rec->ExceptionCode;
+  handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
 
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
   /* Record the context of the current thread.  */
-  th = thread_rec (current_event.dwThreadId, -1);
+  thread_rec (current_event.dwThreadId, -1);
 
   switch (code)
     {
@@ -1166,15 +1185,13 @@ handle_exception (struct target_waitstatus *ourstatus)
           cygwin-specific-signal.  So, ignore SEGVs if they show up
           within the text segment of the DLL itself.  */
        const char *fn;
-       CORE_ADDR addr = (CORE_ADDR) (uintptr_t)
-         current_event.u.Exception.ExceptionRecord.ExceptionAddress;
+       CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress;
 
        if ((!cygwin_exceptions && (addr >= cygwin_load_start
                                    && addr < cygwin_load_end))
            || (find_pc_partial_function (addr, &fn, NULL, NULL)
-               && strncmp (fn, "KERNEL32!IsBad",
-                           strlen ("KERNEL32!IsBad")) == 0))
-         return 0;
+               && startswith (fn, "KERNEL32!IsBad")))
+         return HANDLE_EXCEPTION_UNHANDLED;
       }
 #endif
       break;
@@ -1250,10 +1267,47 @@ handle_exception (struct target_waitstatus *ourstatus)
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
       ourstatus->value.sig = GDB_SIGNAL_ILL;
       break;
+    case MS_VC_EXCEPTION:
+      if (rec->NumberParameters >= 3
+         && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000)
+       {
+         DWORD named_thread_id;
+         windows_thread_info *named_thread;
+         CORE_ADDR thread_name_target;
+
+         DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
+
+         thread_name_target = rec->ExceptionInformation[1];
+         named_thread_id = (DWORD) (0xffffffff & rec->ExceptionInformation[2]);
+
+         if (named_thread_id == (DWORD) -1)
+           named_thread_id = current_event.dwThreadId;
+
+         named_thread = thread_rec (named_thread_id, 0);
+         if (named_thread != NULL)
+           {
+             int thread_name_len;
+             gdb::unique_xmalloc_ptr<char> thread_name;
+
+             thread_name_len = target_read_string (thread_name_target,
+                                                   &thread_name, 1025, NULL);
+             if (thread_name_len > 0)
+               {
+                 thread_name.get ()[thread_name_len - 1] = '\0';
+                 xfree (named_thread->name);
+                 named_thread->name = thread_name.release ();
+               }
+           }
+         ourstatus->value.sig = GDB_SIGNAL_TRAP;
+         result = HANDLE_EXCEPTION_IGNORED;
+         break;
+       }
+       /* treat improperly formed exception as unknown */
+       /* FALLTHROUGH */
     default:
       /* Treat unhandled first chance exceptions specially.  */
       if (current_event.u.Exception.dwFirstChance)
-       return -1;
+       return HANDLE_EXCEPTION_UNHANDLED;
       printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n",
        (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
        host_address_to_string (
@@ -1263,16 +1317,17 @@ handle_exception (struct target_waitstatus *ourstatus)
     }
   exception_count++;
   last_sig = ourstatus->value.sig;
-  return 1;
+  return result;
 }
 
-/* Resume all artificially suspended threads if we are continuing
-   execution.  */
+/* Resume thread specified by ID, or all artificially suspended
+   threads, if we are continuing execution.  KILLED non-zero means we
+   have killed the inferior, so we should ignore weird errors due to
+   threads shutting down.  */
 static BOOL
-windows_continue (DWORD continue_status, int id)
+windows_continue (DWORD continue_status, int id, int killed)
 {
-  int i;
-  thread_info *th;
+  windows_thread_info *th;
   BOOL res;
 
   DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s);\n",
@@ -1297,7 +1352,16 @@ windows_continue (DWORD continue_status, int id)
          }
        if (th->context.ContextFlags)
          {
-           CHECK (SetThreadContext (th->h, &th->context));
+           DWORD ec = 0;
+
+           if (GetExitCodeThread (th->h, &ec)
+               && ec == STILL_ACTIVE)
+             {
+               BOOL status = SetThreadContext (th->h, &th->context);
+
+               if (!killed)
+                 CHECK (status);
+             }
            th->context.ContextFlags = 0;
          }
        if (th->suspended > 0)
@@ -1309,6 +1373,11 @@ windows_continue (DWORD continue_status, int id)
                            current_event.dwThreadId,
                            continue_status);
 
+  if (!res)
+    error (_("Failed to resume program execution"
+            " (ContinueDebugEvent failed, error %u)"),
+          (unsigned int) GetLastError ());
+
   debug_registers_changed = 0;
   return res;
 }
@@ -1328,24 +1397,23 @@ fake_create_process (void)
        (unsigned) GetLastError ());
       /*  We can not debug anything in that case.  */
     }
-  main_thread_id = current_event.dwThreadId;
-  current_thread = windows_add_thread (
-                    ptid_build (current_event.dwProcessId, 0,
-                                current_event.dwThreadId),
-                    current_event.u.CreateThread.hThread,
-                    current_event.u.CreateThread.lpThreadLocalBase);
-  return main_thread_id;
+  current_thread
+    = windows_add_thread (ptid_t (current_event.dwProcessId, 0,
+                                 current_event.dwThreadId),
+                         current_event.u.CreateThread.hThread,
+                         current_event.u.CreateThread.lpThreadLocalBase,
+                         true /* main_thread_p */);
+  return current_event.dwThreadId;
 }
 
-static void
-windows_resume (struct target_ops *ops,
-               ptid_t ptid, int step, enum gdb_signal sig)
+void
+windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
 {
-  thread_info *th;
+  windows_thread_info *th;
   DWORD continue_status = DBG_CONTINUE;
 
   /* A specific PTID means `step only this thread id'.  */
-  int resume_all = ptid_equal (ptid, minus_one_ptid);
+  int resume_all = ptid == minus_one_ptid;
 
   /* If we're continuing all threads, it's the current inferior that
      should be handled specially.  */
@@ -1367,12 +1435,11 @@ windows_resume (struct target_ops *ops,
   structure when passing the exception to the inferior.
   Note that this seems possible in the exception handler itself.  */
        {
-         int i;
-         for (i = 0; xlate[i].them != -1; i++)
-           if (xlate[i].us == sig)
+         for (const xlate_exception &x : xlate)
+           if (x.us == sig)
              {
                current_event.u.Exception.ExceptionRecord.ExceptionCode
-                 = xlate[i].them;
+                 = x.them;
                continue_status = DBG_EXCEPTION_NOT_HANDLED;
                break;
              }
@@ -1382,26 +1449,25 @@ windows_resume (struct target_ops *ops,
            }
        }
 #endif
-       DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
+       DEBUG_EXCEPT(("Can only continue with received signal %d.\n",
          last_sig));
     }
 
   last_sig = GDB_SIGNAL_0;
 
-  DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=%ld, step=%d, sig=%d);\n",
-              ptid_get_pid (ptid), ptid_get_tid (ptid), step, sig));
+  DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=0x%x, step=%d, sig=%d);\n",
+              ptid.pid (), (unsigned) ptid.tid (), step, sig));
 
   /* Get context for currently selected thread.  */
-  th = thread_rec (ptid_get_tid (inferior_ptid), FALSE);
+  th = thread_rec (inferior_ptid.tid (), FALSE);
   if (th)
     {
       if (step)
        {
          /* Single step by setting t bit.  */
          struct regcache *regcache = get_current_regcache ();
-         struct gdbarch *gdbarch = get_regcache_arch (regcache);
-         windows_fetch_inferior_registers (ops, regcache,
-                                           gdbarch_ps_regnum (gdbarch));
+         struct gdbarch *gdbarch = regcache->arch ();
+         fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
          th->context.EFlags |= FLAG_TRACE_BIT;
        }
 
@@ -1425,9 +1491,9 @@ windows_resume (struct target_ops *ops,
      Otherwise complain.  */
 
   if (resume_all)
-    windows_continue (continue_status, -1);
+    windows_continue (continue_status, -1, 0);
   else
-    windows_continue (continue_status, ptid_get_tid (ptid));
+    windows_continue (continue_status, ptid.tid (), 0);
 }
 
 /* Ctrl-C handler used when the inferior is not run in the same console.  The
@@ -1456,17 +1522,17 @@ ctrl_c_handler (DWORD event_type)
   return TRUE;
 }
 
-/* Get the next event from the child.  Return 1 if the event requires
-   handling by WFI (or whatever).  */
+/* Get the next event from the child.  Returns a non-zero thread id if the event
+   requires handling by WFI (or whatever).  */
 static int
 get_windows_debug_event (struct target_ops *ops,
                         int pid, struct target_waitstatus *ourstatus)
 {
   BOOL debug_event;
   DWORD continue_status, event_code;
-  thread_info *th;
-  static thread_info dummy_thread_info;
-  int retval = 0;
+  windows_thread_info *th;
+  static windows_thread_info dummy_thread_info;
+  DWORD thread_id = 0;
 
   last_sig = GDB_SIGNAL_0;
 
@@ -1497,18 +1563,19 @@ get_windows_debug_event (struct target_ops *ops,
              /* Kludge around a Windows bug where first event is a create
                 thread event.  Caused when attached process does not have
                 a main thread.  */
-             retval = fake_create_process ();
-             if (retval)
+             thread_id = fake_create_process ();
+             if (thread_id)
                saw_create++;
            }
          break;
        }
       /* Record the existence of this thread.  */
-      retval = current_event.dwThreadId;
-      th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
-                                        current_event.dwThreadId),
-                            current_event.u.CreateThread.hThread,
-                            current_event.u.CreateThread.lpThreadLocalBase);
+      thread_id = current_event.dwThreadId;
+      th = windows_add_thread
+        (ptid_t (current_event.dwProcessId, 0, current_event.dwThreadId),
+        current_event.u.CreateThread.hThread,
+        current_event.u.CreateThread.lpThreadLocalBase,
+        false /* main_thread_p */);
 
       break;
 
@@ -1517,14 +1584,11 @@ get_windows_debug_event (struct target_ops *ops,
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "EXIT_THREAD_DEBUG_EVENT"));
-
-      if (current_event.dwThreadId != main_thread_id)
-       {
-         windows_delete_thread (ptid_build (current_event.dwProcessId, 0,
-                                            current_event.dwThreadId),
-                                current_event.u.ExitThread.dwExitCode);
-         th = &dummy_thread_info;
-       }
+      windows_delete_thread (ptid_t (current_event.dwProcessId, 0,
+                                    current_event.dwThreadId),
+                            current_event.u.ExitThread.dwExitCode,
+                            false /* main_thread_p */);
+      th = &dummy_thread_info;
       break;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1537,17 +1601,14 @@ get_windows_debug_event (struct target_ops *ops,
        break;
 
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
-      if (main_thread_id)
-       windows_delete_thread (ptid_build (current_event.dwProcessId, 0,
-                                          main_thread_id),
-                              0);
-      main_thread_id = current_event.dwThreadId;
       /* Add the main thread.  */
-      th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
-                                          current_event.dwThreadId),
-            current_event.u.CreateProcessInfo.hThread,
-            current_event.u.CreateProcessInfo.lpThreadLocalBase);
-      retval = current_event.dwThreadId;
+      th = windows_add_thread
+        (ptid_t (current_event.dwProcessId, 0,
+                current_event.dwThreadId),
+        current_event.u.CreateProcessInfo.hThread,
+        current_event.u.CreateProcessInfo.lpThreadLocalBase,
+        true /* main_thread_p */);
+      thread_id = current_event.dwThreadId;
       break;
 
     case EXIT_PROCESS_DEBUG_EVENT:
@@ -1557,16 +1618,34 @@ get_windows_debug_event (struct target_ops *ops,
                     "EXIT_PROCESS_DEBUG_EVENT"));
       if (!windows_initialization_done)
        {
-         target_terminal_ours ();
-         target_mourn_inferior ();
+         target_terminal::ours ();
+         target_mourn_inferior (inferior_ptid);
          error (_("During startup program exited with code 0x%x."),
                 (unsigned int) current_event.u.ExitProcess.dwExitCode);
        }
       else if (saw_create == 1)
        {
-         ourstatus->kind = TARGET_WAITKIND_EXITED;
-         ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
-         retval = main_thread_id;
+         windows_delete_thread (ptid_t (current_event.dwProcessId, 0,
+                                        current_event.dwThreadId),
+                                0, true /* main_thread_p */);
+         DWORD exit_status = current_event.u.ExitProcess.dwExitCode;
+         /* If the exit status looks like a fatal exception, but we
+            don't recognize the exception's code, make the original
+            exit status value available, to avoid losing
+            information.  */
+         int exit_signal
+           = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1;
+         if (exit_signal == -1)
+           {
+             ourstatus->kind = TARGET_WAITKIND_EXITED;
+             ourstatus->value.integer = exit_status;
+           }
+         else
+           {
+             ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+             ourstatus->value.sig = gdb_signal_from_host (exit_signal);
+           }
+         thread_id = current_event.dwThreadId;
        }
       break;
 
@@ -1576,12 +1655,12 @@ get_windows_debug_event (struct target_ops *ops,
                     (unsigned) current_event.dwThreadId,
                     "LOAD_DLL_DEBUG_EVENT"));
       CloseHandle (current_event.u.LoadDll.hFile);
-      if (saw_create != 1)
+      if (saw_create != 1 || ! windows_initialization_done)
        break;
-      catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
+      catch_errors (handle_load_dll);
       ourstatus->kind = TARGET_WAITKIND_LOADED;
       ourstatus->value.integer = 0;
-      retval = main_thread_id;
+      thread_id = current_event.dwThreadId;
       break;
 
     case UNLOAD_DLL_DEBUG_EVENT:
@@ -1589,12 +1668,12 @@ get_windows_debug_event (struct target_ops *ops,
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "UNLOAD_DLL_DEBUG_EVENT"));
-      if (saw_create != 1)
+      if (saw_create != 1 || ! windows_initialization_done)
        break;
-      catch_errors (handle_unload_dll, NULL, (char *) "", RETURN_MASK_ALL);
+      catch_errors (handle_unload_dll);
       ourstatus->kind = TARGET_WAITKIND_LOADED;
       ourstatus->value.integer = 0;
-      retval = main_thread_id;
+      thread_id = current_event.dwThreadId;
       break;
 
     case EXCEPTION_DEBUG_EVENT:
@@ -1606,15 +1685,15 @@ get_windows_debug_event (struct target_ops *ops,
        break;
       switch (handle_exception (ourstatus))
        {
-       case 0:
+       case HANDLE_EXCEPTION_UNHANDLED:
+       default:
          continue_status = DBG_EXCEPTION_NOT_HANDLED;
          break;
-       case 1:
-         retval = current_event.dwThreadId;
+       case HANDLE_EXCEPTION_HANDLED:
+         thread_id = current_event.dwThreadId;
          break;
-       case -1:
-         last_sig = 1;
-         continue_status = -1;
+       case HANDLE_EXCEPTION_IGNORED:
+         continue_status = DBG_CONTINUE;
          break;
        }
       break;
@@ -1626,7 +1705,7 @@ get_windows_debug_event (struct target_ops *ops,
                     "OUTPUT_DEBUG_STRING_EVENT"));
       if (saw_create != 1)
        break;
-      retval = handle_output_debug_string (ourstatus);
+      thread_id = handle_output_debug_string (ourstatus);
       break;
 
     default:
@@ -1640,33 +1719,29 @@ get_windows_debug_event (struct target_ops *ops,
       break;
     }
 
-  if (!retval || saw_create != 1)
+  if (!thread_id || saw_create != 1)
     {
-      if (continue_status == -1)
-       windows_resume (ops, minus_one_ptid, 0, 1);
-      else
-       CHECK (windows_continue (continue_status, -1));
+      CHECK (windows_continue (continue_status, -1, 0));
     }
   else
     {
-      inferior_ptid = ptid_build (current_event.dwProcessId, 0,
-                                 retval);
-      current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
+      inferior_ptid = ptid_t (current_event.dwProcessId, 0, thread_id);
+      current_thread = th;
+      if (!current_thread)
+       current_thread = thread_rec (thread_id, TRUE);
     }
 
 out:
-  return retval;
+  return thread_id;
 }
 
 /* Wait for interesting events to occur in the target process.  */
-static ptid_t
-windows_wait (struct target_ops *ops,
-             ptid_t ptid, struct target_waitstatus *ourstatus, int options)
+ptid_t
+windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+                         int options)
 {
   int pid = -1;
 
-  target_terminal_ours ();
-
   /* We loop when we get a non-standard exception rather than return
      with a SPURIOUS because resume can try and step or modify things,
      which needs a current_thread->h.  But some of these exceptions mark
@@ -1704,11 +1779,11 @@ windows_wait (struct target_ops *ops,
             the user tries to resume the execution in the inferior.
             This is a classic race that we should try to fix one day.  */
       SetConsoleCtrlHandler (&ctrl_c_handler, TRUE);
-      retval = get_windows_debug_event (ops, pid, ourstatus);
+      retval = get_windows_debug_event (this, pid, ourstatus);
       SetConsoleCtrlHandler (&ctrl_c_handler, FALSE);
 
       if (retval)
-       return ptid_build (current_event.dwProcessId, 0, retval);
+       return ptid_t (current_event.dwProcessId, 0, retval);
       else
        {
          int detach = 0;
@@ -1717,37 +1792,22 @@ windows_wait (struct target_ops *ops,
            detach = deprecated_ui_loop_hook (0);
 
          if (detach)
-           windows_kill_inferior (ops);
+           kill ();
        }
     }
 }
 
-/* On certain versions of Windows, the information about ntdll.dll
-   is not available yet at the time we get the LOAD_DLL_DEBUG_EVENT,
-   thus preventing us from reporting this DLL as an SO. This has been
-   witnessed on Windows 8.1, for instance.  A possible explanation
-   is that ntdll.dll might be mapped before the SO info gets created
-   by the Windows system -- ntdll.dll is the first DLL to be reported
-   via LOAD_DLL_DEBUG_EVENT and other DLLs do not seem to suffer from
-   that problem.
-
-   If we indeed are missing ntdll.dll, this function tries to recover
-   from this issue, after the fact.  Do nothing if we encounter any
-   issue trying to locate that DLL.  */
+/* Iterate over all DLLs currently mapped by our inferior, and
+   add them to our list of solibs.  */
 
 static void
-windows_ensure_ntdll_loaded (void)
+windows_add_all_dlls (void)
 {
-  struct so_list *so;
   HMODULE dummy_hmodule;
   DWORD cb_needed;
   HMODULE *hmodules;
   int i;
 
-  for (so = solib_start.next; so != NULL; so = so->next)
-    if (FILENAME_CMP (lbasename (so->so_name), "ntdll.dll") == 0)
-      return;  /* ntdll.dll already loaded, nothing to do.  */
-
   if (EnumProcessModules (current_process_handle, &dummy_hmodule,
                          sizeof (HMODULE), &cb_needed) == 0)
     return;
@@ -1760,7 +1820,7 @@ windows_ensure_ntdll_loaded (void)
                          cb_needed, &cb_needed) == 0)
     return;
 
-  for (i = 0; i < (int) (cb_needed / sizeof (HMODULE)); i++)
+  for (i = 1; i < (int) (cb_needed / sizeof (HMODULE)); i++)
     {
       MODULEINFO mi;
 #ifdef __USEWIDE
@@ -1781,22 +1841,17 @@ windows_ensure_ntdll_loaded (void)
 #else
       name = dll_name;
 #endif
-      if (FILENAME_CMP (lbasename (name), "ntdll.dll") == 0)
-       {
-         solib_end->next = windows_make_so (name, mi.lpBaseOfDll);
-         solib_end = solib_end->next;
-         return;
-       }
+
+      solib_end->next = windows_make_so (name, mi.lpBaseOfDll);
+      solib_end = solib_end->next;
     }
 }
 
 static void
 do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
 {
-  extern int stop_after_trap;
   int i;
   struct inferior *inf;
-  struct thread_info *tp;
 
   last_sig = GDB_SIGNAL_0;
   event_count = 0;
@@ -1811,10 +1866,11 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
 #endif
   current_event.dwProcessId = pid;
   memset (&current_event, 0, sizeof (current_event));
-  push_target (ops);
+  if (!target_is_pushed (ops))
+    push_target (ops);
   disable_breakpoints_in_shlibs ();
   windows_clear_solib ();
-  clear_proceed_status ();
+  clear_proceed_status (0);
   init_wait_for_inferior ();
 
   inf = current_inferior ();
@@ -1825,35 +1881,46 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
      can rely on it.  When attaching, we don't know about any thread
      id here, but that's OK --- nothing should be referencing the
      current thread until we report an event out of windows_wait.  */
-  inferior_ptid = pid_to_ptid (pid);
+  inferior_ptid = ptid_t (pid);
 
-  terminal_init_inferior_with_pgrp (pid);
-  target_terminal_inferior ();
+  target_terminal::init ();
+  target_terminal::inferior ();
 
   windows_initialization_done = 0;
-  inf->control.stop_soon = STOP_QUIETLY;
+
   while (1)
     {
-      stop_after_trap = 1;
-      wait_for_inferior ();
-      tp = inferior_thread ();
-      if (tp->suspend.stop_signal != GDB_SIGNAL_TRAP)
-       resume (0, tp->suspend.stop_signal);
-      else
+      struct target_waitstatus status;
+
+      ops->wait (minus_one_ptid, &status, 0);
+
+      /* Note windows_wait returns TARGET_WAITKIND_SPURIOUS for thread
+        events.  */
+      if (status.kind != TARGET_WAITKIND_LOADED
+         && status.kind != TARGET_WAITKIND_SPURIOUS)
        break;
+
+      ops->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
     }
 
-  /* FIXME: brobecker/2013-12-10: We should try another approach where
-     we first ignore all DLL load/unload events up until this point,
-     and then iterate over all modules to create the associated shared
-     objects.  This is a fairly significant change, however, and we are
-     close to creating a release branch, so we are delaying it a bit,
-     after the branch is created.  */
-  windows_ensure_ntdll_loaded ();
+  /* Now that the inferior has been started and all DLLs have been mapped,
+     we can iterate over all DLLs and load them in.
+
+     We avoid doing it any earlier because, on certain versions of Windows,
+     LOAD_DLL_DEBUG_EVENTs are sometimes not complete.  In particular,
+     we have seen on Windows 8.1 that the ntdll.dll load event does not
+     include the DLL name, preventing us from creating an associated SO.
+     A possible explanation is that ntdll.dll might be mapped before
+     the SO info gets created by the Windows system -- ntdll.dll is
+     the first DLL to be reported via LOAD_DLL_DEBUG_EVENT and other DLLs
+     do not seem to suffer from that problem.
+
+     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.  */
+  windows_add_all_dlls ();
 
   windows_initialization_done = 1;
-  inf->control.stop_soon = NO_STOP_QUIETLY;
-  stop_after_trap = 0;
   return;
 }
 
@@ -1907,8 +1974,9 @@ out:
 }
 
 /* Attach to process PID, then initialize for debugging it.  */
-static void
-windows_attach (struct target_ops *ops, char *args, int from_tty)
+
+void
+windows_nat_target::attach (const char *args, int from_tty)
 {
   BOOL ok;
   DWORD pid;
@@ -1938,35 +2006,34 @@ windows_attach (struct target_ops *ops, char *args, int from_tty)
 #endif
 
   if (!ok)
-    error (_("Can't attach to process."));
+    error (_("Can't attach to process %u (error %u)"),
+          (unsigned) pid, (unsigned) GetLastError ());
 
   DebugSetProcessKillOnExit (FALSE);
 
   if (from_tty)
     {
-      char *exec_file = (char *) get_exec_file (0);
+      const char *exec_file = get_exec_file (0);
 
       if (exec_file)
        printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
-                          target_pid_to_str (pid_to_ptid (pid)));
+                          target_pid_to_str (ptid_t (pid)).c_str ());
       else
        printf_unfiltered ("Attaching to %s\n",
-                          target_pid_to_str (pid_to_ptid (pid)));
-
-      gdb_flush (gdb_stdout);
+                          target_pid_to_str (ptid_t (pid)).c_str ());
     }
 
-  do_initial_windows_stuff (ops, pid, 1);
-  target_terminal_ours ();
+  do_initial_windows_stuff (this, pid, 1);
+  target_terminal::ours ();
 }
 
-static void
-windows_detach (struct target_ops *ops, const char *args, int from_tty)
+void
+windows_nat_target::detach (inferior *inf, int from_tty)
 {
   int detached = 1;
 
-  ptid_t ptid = {-1};
-  windows_resume (ops, ptid, 0, GDB_SIGNAL_0);
+  ptid_t ptid = minus_one_ptid;
+  resume (ptid, 0, GDB_SIGNAL_0);
 
   if (!DebugActiveProcessStop (current_event.dwProcessId))
     {
@@ -1978,23 +2045,76 @@ windows_detach (struct target_ops *ops, const char *args, int from_tty)
 
   if (detached && from_tty)
     {
-      char *exec_file = get_exec_file (0);
+      const char *exec_file = get_exec_file (0);
       if (exec_file == 0)
        exec_file = "";
       printf_unfiltered ("Detaching from program: %s, Pid %u\n", exec_file,
                         (unsigned) current_event.dwProcessId);
-      gdb_flush (gdb_stdout);
     }
 
-  i386_cleanup_dregs ();
+  x86_cleanup_dregs ();
   inferior_ptid = null_ptid;
-  detach_inferior (current_event.dwProcessId);
+  detach_inferior (inf);
 
-  unpush_target (ops);
+  maybe_unpush_target ();
 }
 
-static char *
-windows_pid_to_exec_file (int pid)
+/* Try to determine the executable filename.
+
+   EXE_NAME_RET is a pointer to a buffer whose size is EXE_NAME_MAX_LEN.
+
+   Upon success, the filename is stored inside EXE_NAME_RET, and
+   this function returns nonzero.
+
+   Otherwise, this function returns zero and the contents of
+   EXE_NAME_RET is undefined.  */
+
+static int
+windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len)
+{
+  DWORD len;
+  HMODULE dh_buf;
+  DWORD cbNeeded;
+
+  cbNeeded = 0;
+  if (!EnumProcessModules (current_process_handle, &dh_buf,
+                          sizeof (HMODULE), &cbNeeded) || !cbNeeded)
+    return 0;
+
+  /* We know the executable is always first in the list of modules,
+     which we just fetched.  So no need to fetch more.  */
+
+#ifdef __CYGWIN__
+  {
+    /* Cygwin prefers that the path be in /x/y/z format, so extract
+       the filename into a temporary buffer first, and then convert it
+       to POSIX format into the destination buffer.  */
+    cygwin_buf_t *pathbuf = (cygwin_buf_t *) alloca (exe_name_max_len * sizeof (cygwin_buf_t));
+
+    len = GetModuleFileNameEx (current_process_handle,
+                              dh_buf, pathbuf, exe_name_max_len);
+    if (len == 0)
+      error (_("Error getting executable filename: %u."),
+            (unsigned) GetLastError ());
+    if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, exe_name_ret,
+                         exe_name_max_len) < 0)
+      error (_("Error converting executable filename to POSIX: %d."), errno);
+  }
+#else
+  len = GetModuleFileNameEx (current_process_handle,
+                            dh_buf, exe_name_ret, exe_name_max_len);
+  if (len == 0)
+    error (_("Error getting executable filename: %u."),
+          (unsigned) GetLastError ());
+#endif
+
+    return 1;  /* success */
+}
+
+/* The pid_to_exec_file target_ops method for this platform.  */
+
+char *
+windows_nat_target::pid_to_exec_file (int pid)
 {
   static char path[__PMAX];
 #ifdef __CYGWIN__
@@ -2013,7 +2133,7 @@ windows_pid_to_exec_file (int pid)
 
   /* If we get here then either Cygwin is hosed, this isn't a Cygwin version
      of gdb, or we're trying to debug a non-Cygwin windows executable.  */
-  if (!get_module_name (0, path))
+  if (!windows_get_exec_module_filename (path, sizeof (path)))
     path[0] = '\0';
 
   return path;
@@ -2021,20 +2141,14 @@ windows_pid_to_exec_file (int pid)
 
 /* Print status information about what we're accessing.  */
 
-static void
-windows_files_info (struct target_ops *ignore)
+void
+windows_nat_target::files_info ()
 {
   struct inferior *inf = current_inferior ();
 
   printf_unfiltered ("\tUsing the running image of %s %s.\n",
                     inf->attach_flag ? "attached" : "child",
-                    target_pid_to_str (inferior_ptid));
-}
-
-static void
-windows_open (char *arg, int from_tty)
-{
-  error (_("Use the \"run\" command to start a Unix child process."));
+                    target_pid_to_str (inferior_ptid).c_str ());
 }
 
 /* Modify CreateProcess parameters for use of a new separate console.
@@ -2116,19 +2230,316 @@ clear_win32_environment (char **env)
 }
 #endif
 
+#ifndef __CYGWIN__
+
+/* Redirection of inferior I/O streams for native MS-Windows programs.
+   Unlike on Unix, where this is handled by invoking the inferior via
+   the shell, on MS-Windows we need to emulate the cmd.exe shell.
+
+   The official documentation of the cmd.exe redirection features is here:
+
+     http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx
+
+   (That page talks about Windows XP, but there's no newer
+   documentation, so we assume later versions of cmd.exe didn't change
+   anything.)
+
+   Caveat: the documentation on that page seems to include a few lies.
+   For example, it describes strange constructs 1<&2 and 2<&1, which
+   seem to work only when 1>&2 resp. 2>&1 would make sense, and so I
+   think the cmd.exe parser of the redirection symbols simply doesn't
+   care about the < vs > distinction in these cases.  Therefore, the
+   supported features are explicitly documented below.
+
+   The emulation below aims at supporting all the valid use cases
+   supported by cmd.exe, which include:
+
+     < FILE    redirect standard input from FILE
+     0< FILE   redirect standard input from FILE
+     <&N       redirect standard input from file descriptor N
+     0<&N      redirect standard input from file descriptor N
+     > FILE    redirect standard output to FILE
+     >> FILE   append standard output to FILE
+     1>> FILE  append standard output to FILE
+     >&N       redirect standard output to file descriptor N
+     1>&N      redirect standard output to file descriptor N
+     >>&N      append standard output to file descriptor N
+     1>>&N     append standard output to file descriptor N
+     2> FILE   redirect standard error to FILE
+     2>> FILE  append standard error to FILE
+     2>&N      redirect standard error to file descriptor N
+     2>>&N     append standard error to file descriptor N
+
+     Note that using N > 2 in the above construct is supported, but
+     requires that the corresponding file descriptor be open by some
+     means elsewhere or outside GDB.  Also note that using ">&0" or
+     "<&2" will generally fail, because the file descriptor redirected
+     from is normally open in an incompatible mode (e.g., FD 0 is open
+     for reading only).  IOW, use of such tricks is not recommended;
+     you are on your own.
+
+     We do NOT support redirection of file descriptors above 2, as in
+     "3>SOME-FILE", because MinGW compiled programs don't (supporting
+     that needs special handling in the startup code that MinGW
+     doesn't have).  Pipes are also not supported.
+
+     As for invalid use cases, where the redirection contains some
+     error, the emulation below will detect that and produce some
+     error and/or failure.  But the behavior in those cases is not
+     bug-for-bug compatible with what cmd.exe does in those cases.
+     That's because what cmd.exe does then is not well defined, and
+     seems to be a side effect of the cmd.exe parsing of the command
+     line more than anything else.  For example, try redirecting to an
+     invalid file name, as in "> foo:bar".
+
+     There are also minor syntactic deviations from what cmd.exe does
+     in some corner cases.  For example, it doesn't support the likes
+     of "> &foo" to mean redirect to file named literally "&foo"; we
+     do support that here, because that, too, sounds like some issue
+     with the cmd.exe parser.  Another nicety is that we support
+     redirection targets that use file names with forward slashes,
+     something cmd.exe doesn't -- this comes in handy since GDB
+     file-name completion can be used when typing the command line for
+     the inferior.  */
+
+/* Support routines for redirecting standard handles of the inferior.  */
+
+/* Parse a single redirection spec, open/duplicate the specified
+   file/fd, and assign the appropriate value to one of the 3 standard
+   file descriptors. */
+static int
+redir_open (const char *redir_string, int *inp, int *out, int *err)
+{
+  int *fd, ref_fd = -2;
+  int mode;
+  const char *fname = redir_string + 1;
+  int rc = *redir_string;
+
+  switch (rc)
+    {
+    case '0':
+      fname++;
+      /* FALLTHROUGH */
+    case '<':
+      fd = inp;
+      mode = O_RDONLY;
+      break;
+    case '1': case '2':
+      fname++;
+      /* FALLTHROUGH */
+    case '>':
+      fd = (rc == '2') ? err : out;
+      mode = O_WRONLY | O_CREAT;
+      if (*fname == '>')
+       {
+         fname++;
+         mode |= O_APPEND;
+       }
+      else
+       mode |= O_TRUNC;
+      break;
+    default:
+      return -1;
+    }
+
+  if (*fname == '&' && '0' <= fname[1] && fname[1] <= '9')
+    {
+      /* A reference to a file descriptor.  */
+      char *fdtail;
+      ref_fd = (int) strtol (fname + 1, &fdtail, 10);
+      if (fdtail > fname + 1 && *fdtail == '\0')
+       {
+         /* Don't allow redirection when open modes are incompatible.  */
+         if ((ref_fd == 0 && (fd == out || fd == err))
+             || ((ref_fd == 1 || ref_fd == 2) && fd == inp))
+           {
+             errno = EPERM;
+             return -1;
+           }
+         if (ref_fd == 0)
+           ref_fd = *inp;
+         else if (ref_fd == 1)
+           ref_fd = *out;
+         else if (ref_fd == 2)
+           ref_fd = *err;
+       }
+      else
+       {
+         errno = EBADF;
+         return -1;
+       }
+    }
+  else
+    fname++;   /* skip the separator space */
+  /* If the descriptor is already open, close it.  This allows
+     multiple specs of redirections for the same stream, which is
+     somewhat nonsensical, but still valid and supported by cmd.exe.
+     (But cmd.exe only opens a single file in this case, the one
+     specified by the last redirection spec on the command line.)  */
+  if (*fd >= 0)
+    _close (*fd);
+  if (ref_fd == -2)
+    {
+      *fd = _open (fname, mode, _S_IREAD | _S_IWRITE);
+      if (*fd < 0)
+       return -1;
+    }
+  else if (ref_fd == -1)
+    *fd = -1;  /* reset to default destination */
+  else
+    {
+      *fd = _dup (ref_fd);
+      if (*fd < 0)
+       return -1;
+    }
+  /* _open just sets a flag for O_APPEND, which won't be passed to the
+     inferior, so we need to actually move the file pointer.  */
+  if ((mode & O_APPEND) != 0)
+    _lseek (*fd, 0L, SEEK_END);
+  return 0;
+}
+
+/* Canonicalize a single redirection spec and set up the corresponding
+   file descriptor as specified.  */
+static int
+redir_set_redirection (const char *s, int *inp, int *out, int *err)
+{
+  char buf[__PMAX + 2 + 5]; /* extra space for quotes & redirection string */
+  char *d = buf;
+  const char *start = s;
+  int quote = 0;
+
+  *d++ = *s++; /* copy the 1st character, < or > or a digit */
+  if ((*start == '>' || *start == '1' || *start == '2')
+      && *s == '>')
+    {
+      *d++ = *s++;
+      if (*s == '>' && *start != '>')
+       *d++ = *s++;
+    }
+  else if (*start == '0' && *s == '<')
+    *d++ = *s++;
+  /* cmd.exe recognizes "&N" only immediately after the redirection symbol.  */
+  if (*s != '&')
+    {
+      while (isspace (*s))  /* skip whitespace before file name */
+       s++;
+      *d++ = ' ';          /* separate file name with a single space */
+    }
+
+  /* Copy the file name.  */
+  while (*s)
+    {
+      /* Remove quoting characters from the file name in buf[].  */
+      if (*s == '"')   /* could support '..' quoting here */
+       {
+         if (!quote)
+           quote = *s++;
+         else if (*s == quote)
+           {
+             quote = 0;
+             s++;
+           }
+         else
+           *d++ = *s++;
+       }
+      else if (*s == '\\')
+       {
+         if (s[1] == '"')      /* could support '..' here */
+           s++;
+         *d++ = *s++;
+       }
+      else if (isspace (*s) && !quote)
+       break;
+      else
+       *d++ = *s++;
+      if (d - buf >= sizeof (buf) - 1)
+       {
+         errno = ENAMETOOLONG;
+         return 0;
+       }
+    }
+  *d = '\0';
+
+  /* Windows doesn't allow redirection characters in file names, so we
+     can bail out early if they use them, or if there's no target file
+     name after the redirection symbol.  */
+  if (d[-1] == '>' || d[-1] == '<')
+    {
+      errno = ENOENT;
+      return 0;
+    }
+  if (redir_open (buf, inp, out, err) == 0)
+    return s - start;
+  return 0;
+}
+
+/* Parse the command line for redirection specs and prepare the file
+   descriptors for the 3 standard streams accordingly.  */
+static bool
+redirect_inferior_handles (const char *cmd_orig, char *cmd,
+                          int *inp, int *out, int *err)
+{
+  const char *s = cmd_orig;
+  char *d = cmd;
+  int quote = 0;
+  bool retval = false;
+
+  while (isspace (*s))
+    *d++ = *s++;
+
+  while (*s)
+    {
+      if (*s == '"')   /* could also support '..' quoting here */
+       {
+         if (!quote)
+           quote = *s;
+         else if (*s == quote)
+           quote = 0;
+       }
+      else if (*s == '\\')
+       {
+         if (s[1] == '"')      /* escaped quote char */
+           s++;
+       }
+      else if (!quote)
+       {
+         /* Process a single redirection candidate.  */
+         if (*s == '<' || *s == '>'
+             || ((*s == '1' || *s == '2') && s[1] == '>')
+             || (*s == '0' && s[1] == '<'))
+           {
+             int skip = redir_set_redirection (s, inp, out, err);
+
+             if (skip <= 0)
+               return false;
+             retval = true;
+             s += skip;
+           }
+       }
+      if (*s)
+       *d++ = *s++;
+    }
+  *d = '\0';
+  return retval;
+}
+#endif /* !__CYGWIN__ */
+
 /* Start an inferior windows child process and sets inferior_ptid to its pid.
    EXEC_FILE is the file to run.
    ALLARGS is a string containing the arguments to the program.
    ENV is the environment vector to pass.  Errors reported with error().  */
 
-static void
-windows_create_inferior (struct target_ops *ops, char *exec_file,
-                      char *allargs, char **in_env, int from_tty)
+void
+windows_nat_target::create_inferior (const char *exec_file,
+                                    const std::string &origallargs,
+                                    char **in_env, int from_tty)
 {
   STARTUPINFO si;
 #ifdef __CYGWIN__
   cygwin_buf_t real_path[__PMAX];
   cygwin_buf_t shell[__PMAX]; /* Path to shell */
+  cygwin_buf_t infcwd[__PMAX];
   const char *sh;
   cygwin_buf_t *toexec;
   cygwin_buf_t *cygallargs;
@@ -2138,20 +2549,22 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
   size_t len;
   int tty;
   int ostdin, ostdout, ostderr;
-#else
-  char real_path[__PMAX];
+#else  /* !__CYGWIN__ */
   char shell[__PMAX]; /* Path to shell */
-  char *toexec;
-  char *args;
-  size_t args_len;
-  HANDLE tty;
+  const char *toexec;
+  char *args, *allargs_copy;
+  size_t args_len, allargs_len;
+  int fd_inp = -1, fd_out = -1, fd_err = -1;
+  HANDLE tty = INVALID_HANDLE_VALUE;
+  bool redirected = false;
   char *w32env;
   char *temp;
   size_t envlen;
   int i;
   size_t envsize;
   char **env;
-#endif
+#endif /* !__CYGWIN__ */
+  const char *allargs = origallargs.c_str ();
   PROCESS_INFORMATION pi;
   BOOL ret;
   DWORD flags = 0;
@@ -2160,6 +2573,17 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
   if (!exec_file)
     error (_("No executable specified, use `target exec'."));
 
+  const char *inferior_cwd = get_inferior_cwd ();
+  std::string expanded_infcwd;
+  if (inferior_cwd != NULL)
+    {
+      expanded_infcwd = gdb_tilde_expand (inferior_cwd);
+      /* Mirror slashes on inferior's cwd.  */
+      std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
+                   '/', '\\');
+      inferior_cwd = expanded_infcwd.c_str ();
+    }
+
   memset (&si, 0, sizeof (si));
   si.cb = sizeof (si);
 
@@ -2183,15 +2607,13 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
        error (_("Error starting executable: %d"), errno);
       cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
       mbstowcs (cygallargs, allargs, len);
-#else
+#else  /* !__USEWIDE */
       cygallargs = allargs;
 #endif
     }
   else
     {
-      sh = getenv ("SHELL");
-      if (!sh)
-       sh = "/bin/sh";
+      sh = get_shell ();
       if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, sh, shell, __PMAX) < 0)
        error (_("Error starting executable via shell: %d"), errno);
 #ifdef __USEWIDE
@@ -2199,28 +2621,33 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
            + mbstowcs (NULL, allargs, 0) + 2;
       cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
       swprintf (cygallargs, len, L" -c 'exec %s %s'", exec_file, allargs);
-#else
+#else  /* !__USEWIDE */
       len = (sizeof (" -c 'exec  '") + strlen (exec_file)
             + strlen (allargs) + 2);
       cygallargs = (char *) alloca (len);
       xsnprintf (cygallargs, len, " -c 'exec %s %s'", exec_file, allargs);
-#endif
+#endif /* __USEWIDE */
       toexec = shell;
       flags |= DEBUG_PROCESS;
     }
 
+  if (inferior_cwd != NULL
+      && cygwin_conv_path (CCP_POSIX_TO_WIN_W, inferior_cwd,
+                          infcwd, strlen (inferior_cwd)) < 0)
+    error (_("Error converting inferior cwd: %d"), errno);
+
 #ifdef __USEWIDE
   args = (cygwin_buf_t *) alloca ((wcslen (toexec) + wcslen (cygallargs) + 2)
                                  * sizeof (wchar_t));
   wcscpy (args, toexec);
   wcscat (args, L" ");
   wcscat (args, cygallargs);
-#else
+#else  /* !__USEWIDE */
   args = (cygwin_buf_t *) alloca (strlen (toexec) + strlen (cygallargs) + 2);
   strcpy (args, toexec);
   strcat (args, " ");
   strcat (args, cygallargs);
-#endif
+#endif /* !__USEWIDE */
 
 #ifdef CW_CVT_ENV_TO_WINENV
   /* First try to create a direct Win32 copy of the POSIX environment. */
@@ -2229,7 +2656,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
     flags |= CREATE_UNICODE_ENVIRONMENT;
   else
     /* If that fails, fall back to old method tweaking GDB's environment. */
-#endif
+#endif /* CW_CVT_ENV_TO_WINENV */
     {
       /* Reset all Win32 environment variables to avoid leftover on next run. */
       clear_win32_environment (environ);
@@ -2269,7 +2696,8 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
                       TRUE,    /* inherit handles */
                       flags,   /* start flags */
                       w32_env, /* environment */
-                      NULL,    /* current directory */
+                      inferior_cwd != NULL ? infcwd : NULL, /* current
+                                                               directory */
                       &si,
                       &pi);
   if (w32_env)
@@ -2286,29 +2714,34 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
 
   if (tty >= 0)
     {
-      close (tty);
+      ::close (tty);
       dup2 (ostdin, 0);
       dup2 (ostdout, 1);
       dup2 (ostderr, 2);
-      close (ostdin);
-      close (ostdout);
-      close (ostderr);
+      ::close (ostdin);
+      ::close (ostdout);
+      ::close (ostderr);
     }
-#else
-  toexec = exec_file;
-  /* Build the command line, a space-separated list of tokens where
-     the first token is the name of the module to be executed.
-     To avoid ambiguities introduced by spaces in the module name,
-     we quote it.  */
-  args_len = strlen (toexec) + 2 /* quotes */ + strlen (allargs) + 2;
-  args = alloca (args_len);
-  xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs);
-
-  flags |= DEBUG_ONLY_THIS_PROCESS;
-
-  if (!inferior_io_terminal)
-    tty = INVALID_HANDLE_VALUE;
-  else
+#else  /* !__CYGWIN__ */
+  allargs_len = strlen (allargs);
+  allargs_copy = strcpy ((char *) alloca (allargs_len + 1), allargs);
+  if (strpbrk (allargs_copy, "<>") != NULL)
+    {
+      int e = errno;
+      errno = 0;
+      redirected =
+       redirect_inferior_handles (allargs, allargs_copy,
+                                  &fd_inp, &fd_out, &fd_err);
+      if (errno)
+       warning (_("Error in redirection: %s."), safe_strerror (errno));
+      else
+       errno = e;
+      allargs_len = strlen (allargs_copy);
+    }
+  /* If not all the standard streams are redirected by the command
+     line, use inferior_io_terminal for those which aren't.  */
+  if (inferior_io_terminal
+      && !(fd_inp >= 0 && fd_out >= 0 && fd_err >= 0))
     {
       SECURITY_ATTRIBUTES sa;
       sa.nLength = sizeof(sa);
@@ -2319,15 +2752,41 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
       if (tty == INVALID_HANDLE_VALUE)
        warning (_("Warning: Failed to open TTY %s, error %#x."),
                 inferior_io_terminal, (unsigned) GetLastError ());
+    }
+  if (redirected || tty != INVALID_HANDLE_VALUE)
+    {
+      if (fd_inp >= 0)
+       si.hStdInput = (HANDLE) _get_osfhandle (fd_inp);
+      else if (tty != INVALID_HANDLE_VALUE)
+       si.hStdInput = tty;
       else
-       {
-         si.hStdInput = tty;
-         si.hStdOutput = tty;
-         si.hStdError = tty;
-         si.dwFlags |= STARTF_USESTDHANDLES;
-       }
+       si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+      if (fd_out >= 0)
+       si.hStdOutput = (HANDLE) _get_osfhandle (fd_out);
+      else if (tty != INVALID_HANDLE_VALUE)
+       si.hStdOutput = tty;
+      else
+       si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+      if (fd_err >= 0)
+       si.hStdError = (HANDLE) _get_osfhandle (fd_err);
+      else if (tty != INVALID_HANDLE_VALUE)
+       si.hStdError = tty;
+      else
+       si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+      si.dwFlags |= STARTF_USESTDHANDLES;
     }
 
+  toexec = exec_file;
+  /* Build the command line, a space-separated list of tokens where
+     the first token is the name of the module to be executed.
+     To avoid ambiguities introduced by spaces in the module name,
+     we quote it.  */
+  args_len = strlen (toexec) + 2 /* quotes */ + allargs_len + 2;
+  args = (char *) alloca (args_len);
+  xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs_copy);
+
+  flags |= DEBUG_ONLY_THIS_PROCESS;
+
   /* CreateProcess takes the environment list as a null terminated set of
      strings (i.e. two nulls terminate the list).  */
 
@@ -2341,7 +2800,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
   /* Windows programs expect the environment block to be sorted.  */
   qsort (env, i, sizeof (char *), envvar_cmp);
 
-  w32env = alloca (envlen + 1);
+  w32env = (char *) alloca (envlen + 1);
 
   /* Copy env strings into new buffer.  */
   for (temp = w32env, i = 0; env[i] && *env[i]; i++)
@@ -2361,12 +2820,18 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
                        TRUE,   /* inherit handles */
                        flags,  /* start flags */
                        w32env, /* environment */
-                       NULL,   /* current directory */
+                       inferior_cwd, /* current directory */
                        &si,
                        &pi);
   if (tty != INVALID_HANDLE_VALUE)
     CloseHandle (tty);
-#endif
+  if (fd_inp >= 0)
+    _close (fd_inp);
+  if (fd_out >= 0)
+    _close (fd_out);
+  if (fd_err >= 0)
+    _close (fd_err);
+#endif /* !__CYGWIN__ */
 
   if (!ret)
     error (_("Error creating process %s, (error %u)."),
@@ -2380,30 +2845,29 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
   else
     saw_create = 0;
 
-  do_initial_windows_stuff (ops, pi.dwProcessId, 0);
+  do_initial_windows_stuff (this, pi.dwProcessId, 0);
 
-  /* windows_continue (DBG_CONTINUE, -1); */
+  /* windows_continue (DBG_CONTINUE, -1, 0); */
 }
 
-static void
-windows_mourn_inferior (struct target_ops *ops)
+void
+windows_nat_target::mourn_inferior ()
 {
-  (void) windows_continue (DBG_CONTINUE, -1);
-  i386_cleanup_dregs();
+  (void) windows_continue (DBG_CONTINUE, -1, 0);
+  x86_cleanup_dregs();
   if (open_process_used)
     {
       CHECK (CloseHandle (current_process_handle));
       open_process_used = 0;
     }
-  unpush_target (ops);
-  generic_mourn_inferior ();
+  inf_child_target::mourn_inferior ();
 }
 
 /* Send a SIGINT to the process group.  This acts just like the user typed a
    ^C on the controlling terminal.  */
 
-static void
-windows_stop (ptid_t ptid)
+void
+windows_nat_target::interrupt ()
 {
   DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n"));
   CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId));
@@ -2450,14 +2914,14 @@ windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
     return success ? TARGET_XFER_OK : TARGET_XFER_E_IO;
 }
 
-static void
-windows_kill_inferior (struct target_ops *ops)
+void
+windows_nat_target::kill ()
 {
   CHECK (TerminateProcess (current_process_handle, 0));
 
   for (;;)
     {
-      if (!windows_continue (DBG_CONTINUE, -1))
+      if (!windows_continue (DBG_CONTINUE, -1, 1))
        break;
       if (!WaitForDebugEvent (&current_event, INFINITE))
        break;
@@ -2465,40 +2929,22 @@ windows_kill_inferior (struct target_ops *ops)
        break;
     }
 
-  target_mourn_inferior ();    /* Or just windows_mourn_inferior?  */
-}
-
-static void
-windows_prepare_to_store (struct target_ops *self, struct regcache *regcache)
-{
-  /* Do nothing, since we can store individual regs.  */
-}
-
-static int
-windows_can_run (void)
-{
-  return 1;
+  target_mourn_inferior (inferior_ptid);       /* Or just windows_mourn_inferior?  */
 }
 
-static void
-windows_close (void)
+void
+windows_nat_target::close ()
 {
   DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n",
-               ptid_get_pid (inferior_ptid)));
+               inferior_ptid.pid ()));
 }
 
 /* Convert pid to printable format.  */
-static char *
-windows_pid_to_str (struct target_ops *ops, ptid_t ptid)
+std::string
+windows_nat_target::pid_to_str (ptid_t ptid)
 {
-  static char buf[80];
-
-  if (ptid_get_tid (ptid) != 0)
-    {
-      snprintf (buf, sizeof (buf), "Thread %d.0x%lx",
-               ptid_get_pid (ptid), ptid_get_tid (ptid));
-      return buf;
-    }
+  if (ptid.tid () != 0)
+    return string_printf ("Thread %d.0x%lx", ptid.pid (), ptid.tid ());
 
   return normal_pid_to_str (ptid);
 }
@@ -2521,12 +2967,16 @@ windows_xfer_shared_libraries (struct target_ops *ops,
   obstack_init (&obstack);
   obstack_grow_str (&obstack, "<library-list>\n");
   for (so = solib_start.next; so; so = so->next)
-    windows_xfer_shared_library (so->so_name, (CORE_ADDR)
-                                (uintptr_t) so->lm_info->load_addr,
-                                target_gdbarch (), &obstack);
+    {
+      lm_info_windows *li = (lm_info_windows *) so->lm_info;
+
+      windows_xfer_shared_library (so->so_name, (CORE_ADDR)
+                                  (uintptr_t) li->load_addr,
+                                  target_gdbarch (), &obstack);
+    }
   obstack_grow_str0 (&obstack, "</library-list>\n");
 
-  buf = obstack_finish (&obstack);
+  buf = (const char *) obstack_finish (&obstack);
   len_avail = strlen (buf);
   if (offset >= len_avail)
     len= 0;
@@ -2539,14 +2989,14 @@ windows_xfer_shared_libraries (struct target_ops *ops,
 
   obstack_free (&obstack, NULL);
   *xfered_len = (ULONGEST) len;
-  return TARGET_XFER_OK;
+  return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF;
 }
 
-static enum target_xfer_status
-windows_xfer_partial (struct target_ops *ops, enum target_object object,
-                     const char *annex, gdb_byte *readbuf,
-                     const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
-                     ULONGEST *xfered_len)
+enum target_xfer_status
+windows_nat_target::xfer_partial (enum target_object object,
+                                 const char *annex, gdb_byte *readbuf,
+                                 const gdb_byte *writebuf, ULONGEST offset,
+                                 ULONGEST len, ULONGEST *xfered_len)
 {
   switch (object)
     {
@@ -2554,129 +3004,81 @@ windows_xfer_partial (struct target_ops *ops, enum target_object object,
       return windows_xfer_memory (readbuf, writebuf, offset, len, xfered_len);
 
     case TARGET_OBJECT_LIBRARIES:
-      return windows_xfer_shared_libraries (ops, object, annex, readbuf,
+      return windows_xfer_shared_libraries (this, object, annex, readbuf,
                                            writebuf, offset, len, xfered_len);
 
     default:
-      if (ops->beneath != NULL)
-       return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
-                                             readbuf, writebuf, offset, len,
-                                             xfered_len);
-      return TARGET_XFER_E_IO;
+      if (beneath () == NULL)
+       {
+         /* This can happen when requesting the transfer of unsupported
+            objects before a program has been started (and therefore
+            with the current_target having no target beneath).  */
+         return TARGET_XFER_E_IO;
+       }
+      return beneath ()->xfer_partial (object, annex,
+                                      readbuf, writebuf, offset, len,
+                                      xfered_len);
     }
 }
 
 /* Provide thread local base, i.e. Thread Information Block address.
    Returns 1 if ptid is found and sets *ADDR to thread_local_base.  */
 
-static int
-windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+bool
+windows_nat_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
 {
-  thread_info *th;
+  windows_thread_info *th;
 
-  th = thread_rec (ptid_get_tid (ptid), 0);
+  th = thread_rec (ptid.tid (), 0);
   if (th == NULL)
-    return 0;
+    return false;
 
   if (addr != NULL)
     *addr = th->thread_local_base;
 
-  return 1;
+  return true;
 }
 
-static ptid_t
-windows_get_ada_task_ptid (long lwp, long thread)
+ptid_t
+windows_nat_target::get_ada_task_ptid (long lwp, long thread)
 {
-  return ptid_build (ptid_get_pid (inferior_ptid), 0, lwp);
+  return ptid_t (inferior_ptid.pid (), 0, lwp);
 }
 
-static void
-init_windows_ops (void)
-{
-  windows_ops.to_shortname = "child";
-  windows_ops.to_longname = "Win32 child process";
-  windows_ops.to_doc = "Win32 child process (started by the \"run\" command).";
-  windows_ops.to_open = windows_open;
-  windows_ops.to_close = windows_close;
-  windows_ops.to_attach = windows_attach;
-  windows_ops.to_attach_no_wait = 1;
-  windows_ops.to_detach = windows_detach;
-  windows_ops.to_resume = windows_resume;
-  windows_ops.to_wait = windows_wait;
-  windows_ops.to_fetch_registers = windows_fetch_inferior_registers;
-  windows_ops.to_store_registers = windows_store_inferior_registers;
-  windows_ops.to_prepare_to_store = windows_prepare_to_store;
-  windows_ops.to_xfer_partial = windows_xfer_partial;
-  windows_ops.to_files_info = windows_files_info;
-  windows_ops.to_insert_breakpoint = memory_insert_breakpoint;
-  windows_ops.to_remove_breakpoint = memory_remove_breakpoint;
-  windows_ops.to_terminal_init = terminal_init_inferior;
-  windows_ops.to_terminal_inferior = terminal_inferior;
-  windows_ops.to_terminal_ours_for_output = terminal_ours_for_output;
-  windows_ops.to_terminal_ours = terminal_ours;
-  windows_ops.to_terminal_save_ours = terminal_save_ours;
-  windows_ops.to_terminal_info = child_terminal_info;
-  windows_ops.to_kill = windows_kill_inferior;
-  windows_ops.to_create_inferior = windows_create_inferior;
-  windows_ops.to_mourn_inferior = windows_mourn_inferior;
-  windows_ops.to_can_run = windows_can_run;
-  windows_ops.to_thread_alive = windows_thread_alive;
-  windows_ops.to_pid_to_str = windows_pid_to_str;
-  windows_ops.to_stop = windows_stop;
-  windows_ops.to_stratum = process_stratum;
-  windows_ops.to_has_all_memory = default_child_has_all_memory;
-  windows_ops.to_has_memory = default_child_has_memory;
-  windows_ops.to_has_stack = default_child_has_stack;
-  windows_ops.to_has_registers = default_child_has_registers;
-  windows_ops.to_has_execution = default_child_has_execution;
-  windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
-  windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
-  windows_ops.to_get_tib_address = windows_get_tib_address;
-
-  i386_use_watchpoints (&windows_ops);
-
-  i386_dr_low.set_control = cygwin_set_dr7;
-  i386_dr_low.set_addr = cygwin_set_dr;
-  i386_dr_low.get_addr = cygwin_get_dr;
-  i386_dr_low.get_status = cygwin_get_dr6;
-  i386_dr_low.get_control = cygwin_get_dr7;
-
-  /* i386_dr_low.debug_register_length field is set by
-     calling i386_set_debug_register_length function
-     in processor windows specific native file.  */
-
-  windows_ops.to_magic = OPS_MAGIC;
-}
+/* Implementation of the to_thread_name method.  */
 
-static void
-set_windows_aliases (char *argv0)
+const char *
+windows_nat_target::thread_name (struct thread_info *thr)
 {
-  add_info_alias ("dll", "sharedlibrary", 1);
+  return thread_rec (thr->ptid.tid (), 0)->name;
 }
 
-/* -Wmissing-prototypes */
-extern initialize_file_ftype _initialize_windows_nat;
 
 void
 _initialize_windows_nat (void)
 {
-  struct cmd_list_element *c;
+  x86_dr_low.set_control = cygwin_set_dr7;
+  x86_dr_low.set_addr = cygwin_set_dr;
+  x86_dr_low.get_addr = cygwin_get_dr;
+  x86_dr_low.get_status = cygwin_get_dr6;
+  x86_dr_low.get_control = cygwin_get_dr7;
 
-  init_windows_ops ();
+  /* x86_dr_low.debug_register_length field is set by
+     calling x86_set_debug_register_length function
+     in processor windows specific native file.  */
+
+  add_inf_child_target (&the_windows_nat_target);
 
 #ifdef __CYGWIN__
   cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
 #endif
 
-  c = add_com ("dll-symbols", class_files, dll_symbol_command,
-              _("Load dll library symbols from FILE."));
-  set_cmd_completer (c, filename_completer);
-
-  add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
-
-  add_com_alias ("add-shared-symbol-files", "dll-symbols", class_alias, 1);
-
-  add_com_alias ("assf", "dll-symbols", class_alias, 1);
+  add_com ("signal-event", class_run, signal_event_command, _("\
+Signal a crashed process with event ID, to allow its debugging.\n\
+This command is needed in support of setting up GDB as JIT debugger on \
+MS-Windows.  The command should be invoked from the GDB command line using \
+the '-ex' command-line option.  The ID of the event that blocks the \
+crashed process will be supplied by the Windows JIT debugging mechanism."));
 
 #ifdef __CYGWIN__
   add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\
@@ -2743,8 +3145,6 @@ Show whether to display kernel exceptions in child process."), NULL,
   add_cmd ("selector", class_info, display_selectors,
           _("Display selectors infos."),
           &info_w32_cmdlist);
-  add_target (&windows_ops);
-  deprecated_init_ui_hook = set_windows_aliases;
 }
 
 /* Hardware watchpoint support, adapted from go32-nat.c code.  */
@@ -2804,21 +3204,18 @@ cygwin_get_dr7 (void)
 /* Determine if the thread referenced by "ptid" is alive
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
    it means that the thread has died.  Otherwise it is assumed to be alive.  */
-static int
-windows_thread_alive (struct target_ops *ops, ptid_t ptid)
+
+bool
+windows_nat_target::thread_alive (ptid_t ptid)
 {
   int tid;
 
-  gdb_assert (ptid_get_tid (ptid) != 0);
-  tid = ptid_get_tid (ptid);
+  gdb_assert (ptid.tid () != 0);
+  tid = ptid.tid ();
 
-  return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0
-    ? FALSE : TRUE;
+  return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) != WAIT_OBJECT_0;
 }
 
-/* -Wmissing-prototypes */
-extern initialize_file_ftype _initialize_check_for_gdb_ini;
-
 void
 _initialize_check_for_gdb_ini (void)
 {
@@ -2831,7 +3228,7 @@ _initialize_check_for_gdb_ini (void)
     {
       char *p;
       char *oldini = (char *) alloca (strlen (homedir) +
-                                     sizeof ("/gdb.ini"));
+                                     sizeof ("gdb.ini") + 1);
       strcpy (oldini, homedir);
       p = strchr (oldini, '\0');
       if (p > oldini && !IS_DIR_SEPARATOR (p[-1]))
@@ -2840,9 +3237,9 @@ _initialize_check_for_gdb_ini (void)
       if (access (oldini, 0) == 0)
        {
          int len = strlen (oldini);
-         char *newini = alloca (len + 1);
+         char *newini = (char *) alloca (len + 2);
 
-         xsnprintf (newini, len + 1, "%.*s.gdbinit",
+         xsnprintf (newini, len + 2, "%.*s.gdbinit",
                     (int) (len - (sizeof ("gdb.ini") - 1)), oldini);
          warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini);
        }
@@ -2913,9 +3310,6 @@ bad_GetConsoleFontSize (HANDLE w, DWORD nFont)
   return size;
 }
  
-/* -Wmissing-prototypes */
-extern initialize_file_ftype _initialize_loadable;
-
 /* Load any functions which may not be available in ancient versions
    of Windows.  */
 
@@ -2924,19 +3318,18 @@ _initialize_loadable (void)
 {
   HMODULE hm = NULL;
 
+#define GPA(m, func)                                   \
+  func = (func ## _ftype *) GetProcAddress (m, #func)
+
   hm = LoadLibrary ("kernel32.dll");
   if (hm)
     {
-      DebugActiveProcessStop = (void *)
-       GetProcAddress (hm, "DebugActiveProcessStop");
-      DebugBreakProcess = (void *)
-       GetProcAddress (hm, "DebugBreakProcess");
-      DebugSetProcessKillOnExit = (void *)
-       GetProcAddress (hm, "DebugSetProcessKillOnExit");
-      GetConsoleFontSize = (void *) 
-       GetProcAddress (hm, "GetConsoleFontSize");
-      GetCurrentConsoleFont = (void *) 
-       GetProcAddress (hm, "GetCurrentConsoleFont");
+      GPA (hm, DebugActiveProcessStop);
+      GPA (hm, DebugBreakProcess);
+      GPA (hm, DebugSetProcessKillOnExit);
+      GPA (hm, GetConsoleFontSize);
+      GPA (hm, DebugActiveProcessStop);
+      GPA (hm, GetCurrentConsoleFont);
     }
 
   /* Set variables to dummy versions of these processes if the function
@@ -2958,12 +3351,10 @@ _initialize_loadable (void)
   hm = LoadLibrary ("psapi.dll");
   if (hm)
     {
-      EnumProcessModules = (void *)
-       GetProcAddress (hm, "EnumProcessModules");
-      GetModuleInformation = (void *)
-       GetProcAddress (hm, "GetModuleInformation");
-      GetModuleFileNameEx = (void *)
-       GetProcAddress (hm, GetModuleFileNameEx_name);
+      GPA (hm, EnumProcessModules);
+      GPA (hm, GetModuleInformation);
+      GetModuleFileNameEx = (GetModuleFileNameEx_ftype *)
+        GetProcAddress (hm, GetModuleFileNameEx_name);
     }
 
   if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx)
@@ -2983,15 +3374,15 @@ Use \"file\" or \"dll\" command to load executable/libraries directly."));
   hm = LoadLibrary ("advapi32.dll");
   if (hm)
     {
-      OpenProcessToken = (void *) GetProcAddress (hm, "OpenProcessToken");
-      LookupPrivilegeValueA = (void *)
-       GetProcAddress (hm, "LookupPrivilegeValueA");
-      AdjustTokenPrivileges = (void *)
-       GetProcAddress (hm, "AdjustTokenPrivileges");
+      GPA (hm, OpenProcessToken);
+      GPA (hm, LookupPrivilegeValueA);
+      GPA (hm, AdjustTokenPrivileges);
       /* Only need to set one of these since if OpenProcessToken fails nothing
         else is needed.  */
       if (!OpenProcessToken || !LookupPrivilegeValueA
          || !AdjustTokenPrivileges)
        OpenProcessToken = bad_OpenProcessToken;
     }
+
+#undef GPA
 }
This page took 0.061665 seconds and 4 git commands to generate.