gdb/jit: apply minor cleanup and modernization
[deliverable/binutils-gdb.git] / gdb / windows-nat.c
index 24841fd1f27d54d48fe72301b056b65209a8674d..188a920cbb061f0d8639340ffec40b7d9afd4b3b 100644 (file)
@@ -72,8 +72,7 @@
 #include "gdbsupport/gdb_wait.h"
 #include "nat/windows-nat.h"
 
-#define STATUS_WX86_BREAKPOINT 0x4000001F
-#define STATUS_WX86_SINGLE_STEP 0x4000001E
+using namespace windows_nat;
 
 #define AdjustTokenPrivileges          dyn_AdjustTokenPrivileges
 #define DebugActiveProcessStop         dyn_DebugActiveProcessStop
@@ -211,19 +210,6 @@ 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
@@ -231,10 +217,10 @@ typedef enum
 #endif
 
 #define CHECK(x)       check (x, __FILE__,__LINE__)
-#define DEBUG_EXEC(x)  if (debug_exec)         printf_unfiltered x
-#define DEBUG_EVENTS(x)        if (debug_events)       printf_unfiltered x
-#define DEBUG_MEM(x)   if (debug_memory)       printf_unfiltered x
-#define DEBUG_EXCEPT(x)        if (debug_exceptions)   printf_unfiltered x
+#define DEBUG_EXEC(x)  if (debug_exec)         debug_printf x
+#define DEBUG_EVENTS(x)        if (debug_events)       debug_printf x
+#define DEBUG_MEM(x)   if (debug_memory)       debug_printf x
+#define DEBUG_EXCEPT(x)        if (debug_exceptions)   debug_printf x
 
 static void cygwin_set_dr (int i, CORE_ADDR addr);
 static void cygwin_set_dr7 (unsigned long val);
@@ -242,27 +228,13 @@ static CORE_ADDR cygwin_get_dr (int i);
 static unsigned long cygwin_get_dr6 (void);
 static unsigned long cygwin_get_dr7 (void);
 
-static enum gdb_signal last_sig = GDB_SIGNAL_0;
-/* Set if a signal was received from the debugged process.  */
-
 static std::vector<windows_thread_info *> thread_list;
 
-/* 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 windows_thread_info *current_thread;    /* Info on currently selected thread */
-static EXCEPTION_RECORD siginfo_er;    /* Contents of $_siginfo */
-
 /* Counts of things.  */
-static int exception_count = 0;
-static int event_count = 0;
 static int saw_create;
 static int open_process_used = 0;
 #ifdef __x86_64__
 static bool wow64_process = false;
-static bool ignore_first_breakpoint = false;
 #endif
 
 /* User options.  */
@@ -343,6 +315,18 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
   void fetch_registers (struct regcache *, int) override;
   void store_registers (struct regcache *, int) override;
 
+  bool stopped_by_sw_breakpoint () override
+  {
+    windows_thread_info *th
+      = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+    return th->stopped_at_software_breakpoint;
+  }
+
+  bool supports_stopped_by_sw_breakpoint () override
+  {
+    return true;
+  }
+
   enum target_xfer_status xfer_partial (enum target_object object,
                                        const char *annex,
                                        gdb_byte *readbuf,
@@ -374,6 +358,8 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
   const char *thread_name (struct thread_info *) override;
 
   int get_windows_debug_event (int pid, struct target_waitstatus *ourstatus);
+
+  void do_initial_windows_stuff (DWORD pid, bool attaching);
 };
 
 static windows_nat_target the_windows_nat_target;
@@ -404,26 +390,13 @@ check (BOOL ok, const char *file, int line)
                     (unsigned) GetLastError ());
 }
 
-/* Possible values to pass to 'thread_rec'.  */
-enum thread_disposition_type
-{
-  /* Do not invalidate the thread's context, and do not suspend the
-     thread.  */
-  DONT_INVALIDATE_CONTEXT,
-  /* Invalidate the context, but do not suspend the thread.  */
-  DONT_SUSPEND,
-  /* Invalidate the context and suspend the thread.  */
-  INVALIDATE_CONTEXT
-};
+/* See nat/windows-nat.h.  */
 
-/* Find a thread record given a thread id.  THREAD_DISPOSITION
-   controls whether the thread is suspended, and whether the context
-   is invalidated.  */
-static windows_thread_info *
-thread_rec (DWORD id, enum thread_disposition_type disposition)
+windows_thread_info *
+windows_nat::thread_rec (ptid_t ptid, thread_disposition_type disposition)
 {
   for (windows_thread_info *th : thread_list)
-    if (th->tid == id)
+    if (th->tid == ptid.lwp ())
       {
        if (!th->suspended)
          {
@@ -433,7 +406,7 @@ thread_rec (DWORD id, enum thread_disposition_type disposition)
                /* Nothing.  */
                break;
              case INVALIDATE_CONTEXT:
-               if (id != current_event.dwThreadId)
+               if (ptid.lwp () != current_event.dwThreadId)
                  th->suspend ();
                th->reload_context = true;
                break;
@@ -461,13 +434,10 @@ static windows_thread_info *
 windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p)
 {
   windows_thread_info *th;
-  DWORD id;
 
   gdb_assert (ptid.lwp () != 0);
 
-  id = ptid.lwp ();
-
-  if ((th = thread_rec (id, DONT_INVALIDATE_CONTEXT)))
+  if ((th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
     return th;
 
   CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
@@ -477,7 +447,7 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p)
   if (wow64_process)
     base += 0x2000;
 #endif
-  th = new windows_thread_info (id, h, base);
+  th = new windows_thread_info (ptid.lwp (), h, base);
   thread_list.push_back (th);
 
   /* Add this new thread to the list of threads.
@@ -613,6 +583,10 @@ windows_fetch_one_register (struct regcache *regcache,
   struct gdbarch *gdbarch = regcache->arch ();
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
+  gdb_assert (!gdbarch_read_pc_p (gdbarch));
+  gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
+  gdb_assert (!gdbarch_write_pc_p (gdbarch));
+
   if (r == I387_FISEG_REGNUM (tdep))
     {
       long l = *((long *) context_offset) & 0xffff;
@@ -632,14 +606,38 @@ windows_fetch_one_register (struct regcache *regcache,
       regcache->raw_supply (r, (char *) &l);
     }
   else
-    regcache->raw_supply (r, context_offset);
+    {
+      if (th->stopped_at_software_breakpoint
+         && !th->pc_adjusted
+         && r == gdbarch_pc_regnum (gdbarch))
+       {
+         int size = register_size (gdbarch, r);
+         if (size == 4)
+           {
+             uint32_t value;
+             memcpy (&value, context_offset, size);
+             value -= gdbarch_decr_pc_after_break (gdbarch);
+             memcpy (context_offset, &value, size);
+           }
+         else
+           {
+             gdb_assert (size == 8);
+             uint64_t value;
+             memcpy (&value, context_offset, size);
+             value -= gdbarch_decr_pc_after_break (gdbarch);
+             memcpy (context_offset, &value, size);
+           }
+         /* Make sure we only rewrite the PC a single time.  */
+         th->pc_adjusted = true;
+       }
+      regcache->raw_supply (r, context_offset);
+    }
 }
 
 void
 windows_nat_target::fetch_registers (struct regcache *regcache, int r)
 {
-  DWORD tid = regcache->ptid ().lwp ();
-  windows_thread_info *th = thread_rec (tid, INVALIDATE_CONTEXT);
+  windows_thread_info *th = thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
 
   /* Check if TH exists.  Windows sometimes uses a non-existent
      thread id in its events.  */
@@ -734,8 +732,7 @@ windows_store_one_register (const struct regcache *regcache,
 void
 windows_nat_target::store_registers (struct regcache *regcache, int r)
 {
-  DWORD tid = regcache->ptid ().lwp ();
-  windows_thread_info *th = thread_rec (tid, INVALIDATE_CONTEXT);
+  windows_thread_info *th = thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
 
   /* Check if TH exists.  Windows sometimes uses a non-existent
      thread id in its events.  */
@@ -830,7 +827,10 @@ windows_make_so (const char *name, LPVOID load_addr)
          free (rname);
        }
       else
-       error (_("dll path too long"));
+       {
+         warning (_("dll path for \"%s\" too long or inaccessible"), name);
+         strcpy (so->so_name, so->so_original_name);
+       }
     }
   /* Record cygwin1.dll .text start/end.  */
   p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
@@ -838,7 +838,7 @@ windows_make_so (const char *name, LPVOID load_addr)
     {
       asection *text = NULL;
 
-      gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386", -1));
+      gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386"));
 
       if (abfd == NULL)
        return so;
@@ -861,68 +861,13 @@ windows_make_so (const char *name, LPVOID load_addr)
   return so;
 }
 
-static char *
-get_image_name (HANDLE h, void *address, int unicode)
-{
-#ifdef __CYGWIN__
-  static char buf[__PMAX];
-#else
-  static char buf[(2 * __PMAX) + 1];
-#endif
-  DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
-  char *address_ptr;
-  int len = 0;
-  char b[2];
-  SIZE_T done;
-
-  /* Attempt to read the name of the dll that was detected.
-     This is documented to work only when actively debugging
-     a program.  It will not work for attached processes.  */
-  if (address == NULL)
-    return NULL;
-
-  /* See if we could read the address of a string, and that the
-     address isn't null.  */
-  if (!ReadProcessMemory (h, address,  &address_ptr,
-                         sizeof (address_ptr), &done)
-      || done != sizeof (address_ptr) || !address_ptr)
-    return NULL;
-
-  /* Find the length of the string.  */
-  while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
-        && (b[0] != 0 || b[size - 1] != 0) && done == size)
-    continue;
-
-  if (!unicode)
-    ReadProcessMemory (h, address_ptr, buf, len, &done);
-  else
-    {
-      WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
-      ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
-                        &done);
-#ifdef __CYGWIN__
-      wcstombs (buf, unicode_address, __PMAX);
-#else
-      WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, sizeof buf,
-                          0, 0);
-#endif
-    }
-
-  return buf;
-}
+/* See nat/windows-nat.h.  */
 
-/* Handle a DLL load event, and return 1.
-
-   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_load_dll ()
+void
+windows_nat::handle_load_dll ()
 {
   LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
-  char *dll_name;
+  const char *dll_name;
 
   /* Try getting the DLL name via the lpImageName field of the event.
      Note that Microsoft documents this fields as strictly optional,
@@ -952,16 +897,10 @@ windows_free_so (struct so_list *so)
   xfree (so);
 }
 
-/* Handle a DLL unload event.
-   Return 1 if successful, or zero otherwise.
+/* See nat/windows-nat.h.  */
 
-   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 ()
+void
+windows_nat::handle_unload_dll ()
 {
   LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll;
   struct so_list *so;
@@ -1045,19 +984,18 @@ signal_event_command (const char *args, int from_tty)
   CloseHandle ((HANDLE) event_id);
 }
 
-/* Handle DEBUG_STRING output from child process.
-   Cygwin prepends its messages with a "cygwin:".  Interpret this as
-   a Cygwin signal.  Otherwise just print the string as a warning.  */
-static int
-handle_output_debug_string (struct target_waitstatus *ourstatus)
+/* See nat/windows-nat.h.  */
+
+int
+windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus)
 {
-  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.get ()))
+  gdb::unique_xmalloc_ptr<char> s
+    = (target_read_string
+       ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData,
+       1024));
+  if (s == nullptr || !*(s.get ()))
     /* nothing to do */;
   else if (!startswith (s.get (), _CYGWIN_SIGNAL_STRING))
     {
@@ -1197,56 +1135,60 @@ display_selector (HANDLE thread, DWORD sel)
 static void
 display_selectors (const char * args, int from_tty)
 {
-  if (!current_thread)
+  if (inferior_ptid == null_ptid)
     {
       puts_filtered ("Impossible to display selectors now.\n");
       return;
     }
+
+  windows_thread_info *current_windows_thread
+    = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+
   if (!args)
     {
 #ifdef __x86_64__
       if (wow64_process)
        {
          puts_filtered ("Selector $cs\n");
-         display_selector (current_thread->h,
-                           current_thread->wow64_context.SegCs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->wow64_context.SegCs);
          puts_filtered ("Selector $ds\n");
-         display_selector (current_thread->h,
-                           current_thread->wow64_context.SegDs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->wow64_context.SegDs);
          puts_filtered ("Selector $es\n");
-         display_selector (current_thread->h,
-                           current_thread->wow64_context.SegEs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->wow64_context.SegEs);
          puts_filtered ("Selector $ss\n");
-         display_selector (current_thread->h,
-                           current_thread->wow64_context.SegSs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->wow64_context.SegSs);
          puts_filtered ("Selector $fs\n");
-         display_selector (current_thread->h,
-                           current_thread->wow64_context.SegFs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->wow64_context.SegFs);
          puts_filtered ("Selector $gs\n");
-         display_selector (current_thread->h,
-                           current_thread->wow64_context.SegGs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->wow64_context.SegGs);
        }
       else
 #endif
        {
          puts_filtered ("Selector $cs\n");
-         display_selector (current_thread->h,
-                           current_thread->context.SegCs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->context.SegCs);
          puts_filtered ("Selector $ds\n");
-         display_selector (current_thread->h,
-                           current_thread->context.SegDs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->context.SegDs);
          puts_filtered ("Selector $es\n");
-         display_selector (current_thread->h,
-                           current_thread->context.SegEs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->context.SegEs);
          puts_filtered ("Selector $ss\n");
-         display_selector (current_thread->h,
-                           current_thread->context.SegSs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->context.SegSs);
          puts_filtered ("Selector $fs\n");
-         display_selector (current_thread->h,
-                           current_thread->context.SegFs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->context.SegFs);
          puts_filtered ("Selector $gs\n");
-         display_selector (current_thread->h,
-                           current_thread->context.SegGs);
+         display_selector (current_windows_thread->h,
+                           current_windows_thread->context.SegGs);
        }
     }
   else
@@ -1254,191 +1196,72 @@ display_selectors (const char * args, int from_tty)
       int sel;
       sel = parse_and_eval_long (args);
       printf_filtered ("Selector \"%s\"\n",args);
-      display_selector (current_thread->h, sel);
+      display_selector (current_windows_thread->h, sel);
     }
 }
 
-#define DEBUG_EXCEPTION_SIMPLE(x)       if (debug_exceptions) \
-  printf_unfiltered ("gdb: Target exception %s at %s\n", x, \
-    host_address_to_string (\
-      current_event.u.Exception.ExceptionRecord.ExceptionAddress))
+/* See nat/windows-nat.h.  */
 
-static handle_exception_result
-handle_exception (struct target_waitstatus *ourstatus)
+bool
+windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
 {
-  EXCEPTION_RECORD *rec = &current_event.u.Exception.ExceptionRecord;
-  DWORD code = rec->ExceptionCode;
-  handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
-
-  memcpy (&siginfo_er, rec, sizeof siginfo_er);
+  if (rec->NumberParameters >= 3
+      && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000)
+    {
+      DWORD named_thread_id;
+      windows_thread_info *named_thread;
+      CORE_ADDR thread_name_target;
 
-  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      thread_name_target = rec->ExceptionInformation[1];
+      named_thread_id = (DWORD) (0xffffffff & rec->ExceptionInformation[2]);
 
-  /* Record the context of the current thread.  */
-  thread_rec (current_event.dwThreadId, DONT_SUSPEND);
+      if (named_thread_id == (DWORD) -1)
+       named_thread_id = current_event.dwThreadId;
 
-  switch (code)
-    {
-    case EXCEPTION_ACCESS_VIOLATION:
-      DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
-      ourstatus->value.sig = GDB_SIGNAL_SEGV;
-#ifdef __CYGWIN__
-      {
-       /* See if the access violation happened within the cygwin DLL
-          itself.  Cygwin uses a kind of exception handling to deal
-          with passed-in invalid addresses.  gdb should not treat
-          these as real SEGVs since they will be silently handled by
-          cygwin.  A real SEGV will (theoretically) be caught by
-          cygwin later in the process and will be sent as a
-          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) rec->ExceptionAddress;
-
-       if ((!cygwin_exceptions && (addr >= cygwin_load_start
-                                   && addr < cygwin_load_end))
-           || (find_pc_partial_function (addr, &fn, NULL, NULL)
-               && startswith (fn, "KERNEL32!IsBad")))
-         return HANDLE_EXCEPTION_UNHANDLED;
-      }
-#endif
-      break;
-    case STATUS_STACK_OVERFLOW:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_SEGV;
-      break;
-    case STATUS_FLOAT_DENORMAL_OPERAND:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
-      DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_INEXACT_RESULT:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_INVALID_OPERATION:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_OVERFLOW:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_STACK_CHECK:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_UNDERFLOW:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_FLOAT_DIVIDE_BY_ZERO:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_INTEGER_DIVIDE_BY_ZERO:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case STATUS_INTEGER_OVERFLOW:
-      DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
-      break;
-    case EXCEPTION_BREAKPOINT:
-#ifdef __x86_64__
-      if (ignore_first_breakpoint)
+      named_thread = thread_rec (ptid_t (current_event.dwProcessId,
+                                        named_thread_id, 0),
+                                DONT_INVALIDATE_CONTEXT);
+      if (named_thread != NULL)
        {
-         /* For WOW64 processes, there are always 2 breakpoint exceptions
-            on startup, first a BREAKPOINT for the 64bit ntdll.dll,
-            then a WX86_BREAKPOINT for the 32bit ntdll.dll.
-            Here we only care about the WX86_BREAKPOINT's.  */
-         ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-         ignore_first_breakpoint = false;
+         int thread_name_len;
+         gdb::unique_xmalloc_ptr<char> thread_name
+           = target_read_string (thread_name_target, 1025, &thread_name_len);
+         if (thread_name_len > 0)
+           {
+             thread_name.get ()[thread_name_len - 1] = '\0';
+             named_thread->name = std::move (thread_name);
+           }
        }
-#endif
-      /* FALLTHROUGH */
-    case STATUS_WX86_BREAKPOINT:
-      DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
-      break;
-    case DBG_CONTROL_C:
-      DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
-      ourstatus->value.sig = GDB_SIGNAL_INT;
-      break;
-    case DBG_CONTROL_BREAK:
-      DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
-      ourstatus->value.sig = GDB_SIGNAL_INT;
-      break;
-    case EXCEPTION_SINGLE_STEP:
-    case STATUS_WX86_SINGLE_STEP:
-      DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP");
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
-      break;
-    case EXCEPTION_ILLEGAL_INSTRUCTION:
-      DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
-      break;
-    case EXCEPTION_PRIV_INSTRUCTION:
-      DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
-      break;
-    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
-      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]);
+      return true;
+    }
 
-         if (named_thread_id == (DWORD) -1)
-           named_thread_id = current_event.dwThreadId;
+  return false;
+}
 
-         named_thread = thread_rec (named_thread_id, DONT_INVALIDATE_CONTEXT);
-         if (named_thread != NULL)
-           {
-             int thread_name_len;
-             gdb::unique_xmalloc_ptr<char> thread_name;
+/* See nat/windows-nat.h.  */
 
-             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';
-                 named_thread->name = std::move (thread_name);
-               }
-           }
-         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 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 (
-         current_event.u.Exception.ExceptionRecord.ExceptionAddress));
-      ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
-      break;
-    }
-  exception_count++;
-  last_sig = ourstatus->value.sig;
-  return result;
+bool
+windows_nat::handle_access_violation (const EXCEPTION_RECORD *rec)
+{
+#ifdef __CYGWIN__
+  /* See if the access violation happened within the cygwin DLL
+     itself.  Cygwin uses a kind of exception handling to deal with
+     passed-in invalid addresses.  gdb should not treat these as real
+     SEGVs since they will be silently handled by cygwin.  A real SEGV
+     will (theoretically) be caught by cygwin later in the process and
+     will be sent as a 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) rec->ExceptionAddress;
+
+  if ((!cygwin_exceptions && (addr >= cygwin_load_start
+                             && addr < cygwin_load_end))
+      || (find_pc_partial_function (addr, &fn, NULL, NULL)
+         && startswith (fn, "KERNEL32!IsBad")))
+    return true;
+#endif
+  return false;
 }
 
 /* Resume thread specified by ID, or all artificially suspended
@@ -1450,16 +1273,16 @@ windows_continue (DWORD continue_status, int id, int killed)
 {
   BOOL res;
 
-  DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s);\n",
-                 (unsigned) current_event.dwProcessId,
-                 (unsigned) current_event.dwThreadId,
-                 continue_status == DBG_CONTINUE ?
-                 "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED"));
+  desired_stop_thread_id = id;
+
+  if (matching_pending_stop (debug_events))
+    return TRUE;
 
   for (windows_thread_info *th : thread_list)
-    if ((id == -1 || id == (int) th->tid)
-       && th->suspended)
+    if (id == -1 || id == (int) th->tid)
       {
+       if (!th->suspended)
+         continue;
 #ifdef __x86_64__
        if (wow64_process)
          {
@@ -1519,10 +1342,14 @@ windows_continue (DWORD continue_status, int id, int killed)
          }
        th->resume ();
       }
+    else
+      {
+       /* When single-stepping a specific thread, other threads must
+          be suspended.  */
+       th->suspend ();
+      }
 
-  res = ContinueDebugEvent (current_event.dwProcessId,
-                           current_event.dwThreadId,
-                           continue_status);
+  res = continue_last_debug_event (continue_status, debug_events);
 
   if (!res)
     error (_("Failed to resume program execution"
@@ -1548,12 +1375,11 @@ fake_create_process (void)
        (unsigned) GetLastError ());
       /*  We can not debug anything in that case.  */
     }
-  current_thread
-    = windows_add_thread (ptid_t (current_event.dwProcessId,
-                                 current_event.dwThreadId, 0),
-                         current_event.u.CreateThread.hThread,
-                         current_event.u.CreateThread.lpThreadLocalBase,
-                         true /* main_thread_p */);
+  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;
 }
 
@@ -1610,7 +1436,7 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
               ptid.pid (), (unsigned) ptid.lwp (), step, sig));
 
   /* Get context for currently selected thread.  */
-  th = thread_rec (inferior_ptid.lwp (), DONT_INVALIDATE_CONTEXT);
+  th = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
   if (th)
     {
 #ifdef __x86_64__
@@ -1713,21 +1539,33 @@ windows_nat_target::get_windows_debug_event (int pid,
 {
   BOOL debug_event;
   DWORD continue_status, event_code;
-  windows_thread_info *th;
-  static windows_thread_info dummy_thread_info (0, 0, 0);
   DWORD thread_id = 0;
 
+  /* If there is a relevant pending stop, report it now.  See the
+     comment by the definition of "pending_stops" for details on why
+     this is needed.  */
+  gdb::optional<pending_stop> stop = fetch_pending_stop (debug_events);
+  if (stop.has_value ())
+    {
+      thread_id = stop->thread_id;
+      *ourstatus = stop->status;
+
+      ptid_t ptid (current_event.dwProcessId, thread_id);
+      windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT);
+      th->reload_context = 1;
+
+      return thread_id;
+    }
+
   last_sig = GDB_SIGNAL_0;
 
-  if (!(debug_event = WaitForDebugEvent (&current_event, 1000)))
+  if (!(debug_event = wait_for_debug_event (&current_event, 1000)))
     goto out;
 
-  event_count++;
   continue_status = DBG_CONTINUE;
 
   event_code = current_event.dwDebugEventCode;
   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-  th = NULL;
   have_saved_context = 0;
 
   switch (event_code)
@@ -1753,7 +1591,7 @@ windows_nat_target::get_windows_debug_event (int pid,
        }
       /* Record the existence of this thread.  */
       thread_id = current_event.dwThreadId;
-      th = windows_add_thread
+      windows_add_thread
         (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
         current_event.u.CreateThread.hThread,
         current_event.u.CreateThread.lpThreadLocalBase,
@@ -1770,7 +1608,6 @@ windows_nat_target::get_windows_debug_event (int pid,
                                     current_event.dwThreadId, 0),
                             current_event.u.ExitThread.dwExitCode,
                             false /* main_thread_p */);
-      th = &dummy_thread_info;
       break;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1784,7 +1621,7 @@ windows_nat_target::get_windows_debug_event (int pid,
 
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
       /* Add the main thread.  */
-      th = windows_add_thread
+      windows_add_thread
         (ptid_t (current_event.dwProcessId,
                 current_event.dwThreadId, 0),
         current_event.u.CreateProcessInfo.hThread,
@@ -1865,7 +1702,7 @@ windows_nat_target::get_windows_debug_event (int pid,
                     "EXCEPTION_DEBUG_EVENT"));
       if (saw_create != 1)
        break;
-      switch (handle_exception (ourstatus))
+      switch (handle_exception (ourstatus, debug_exceptions))
        {
        case HANDLE_EXCEPTION_UNHANDLED:
        default:
@@ -1903,14 +1740,31 @@ windows_nat_target::get_windows_debug_event (int pid,
 
   if (!thread_id || saw_create != 1)
     {
-      CHECK (windows_continue (continue_status, -1, 0));
+      CHECK (windows_continue (continue_status, desired_stop_thread_id, 0));
     }
-  else
+  else if (desired_stop_thread_id != -1 && desired_stop_thread_id != thread_id)
     {
-      inferior_ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
-      current_thread = th;
-      if (!current_thread)
-       current_thread = thread_rec (thread_id, INVALIDATE_CONTEXT);
+      /* Pending stop.  See the comment by the definition of
+        "pending_stops" for details on why this is needed.  */
+      DEBUG_EVENTS (("get_windows_debug_event - "
+                    "unexpected stop in 0x%x (expecting 0x%x)\n",
+                    thread_id, desired_stop_thread_id));
+
+      if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+         && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
+              == EXCEPTION_BREAKPOINT)
+             || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+                 == STATUS_WX86_BREAKPOINT))
+         && windows_initialization_done)
+       {
+         ptid_t ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
+         windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT);
+         th->stopped_at_software_breakpoint = true;
+         th->pc_adjusted = false;
+       }
+      pending_stops.push_back ({thread_id, *ourstatus, current_event});
+      thread_id = 0;
+      CHECK (windows_continue (continue_status, desired_stop_thread_id, 0));
     }
 
 out:
@@ -1965,7 +1819,32 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
       SetConsoleCtrlHandler (&ctrl_c_handler, FALSE);
 
       if (retval)
-       return ptid_t (current_event.dwProcessId, retval, 0);
+       {
+         ptid_t result = ptid_t (current_event.dwProcessId, retval, 0);
+
+         if (ourstatus->kind != TARGET_WAITKIND_EXITED
+             && ourstatus->kind !=  TARGET_WAITKIND_SIGNALLED)
+           {
+             windows_thread_info *th = thread_rec (result, INVALIDATE_CONTEXT);
+
+             if (th != nullptr)
+               {
+                 th->stopped_at_software_breakpoint = false;
+                 if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+                     && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
+                          == EXCEPTION_BREAKPOINT)
+                         || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+                             == STATUS_WX86_BREAKPOINT))
+                     && windows_initialization_done)
+                   {
+                     th->stopped_at_software_breakpoint = true;
+                     th->pc_adjusted = false;
+                   }
+               }
+           }
+
+         return result;
+       }
       else
        {
          int detach = 0;
@@ -2096,15 +1975,13 @@ windows_add_all_dlls (void)
     }
 }
 
-static void
-do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
+void
+windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
 {
   int i;
   struct inferior *inf;
 
   last_sig = GDB_SIGNAL_0;
-  event_count = 0;
-  exception_count = 0;
   open_process_used = 0;
   debug_registers_changed = 0;
   debug_registers_used = 0;
@@ -2115,8 +1992,8 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
 #endif
   current_event.dwProcessId = pid;
   memset (&current_event, 0, sizeof (current_event));
-  if (!target_is_pushed (ops))
-    push_target (ops);
+  if (!target_is_pushed (this))
+    push_target (this);
   disable_breakpoints_in_shlibs ();
   windows_clear_solib ();
   clear_proceed_status (0);
@@ -2141,22 +2018,18 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
   inferior_appeared (inf, pid);
   inf->attach_flag = attaching;
 
-  /* Make the new process the current inferior, so terminal handling
-     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 = ptid_t (pid);
-
   target_terminal::init ();
   target_terminal::inferior ();
 
   windows_initialization_done = 0;
 
+  ptid_t last_ptid;
+
   while (1)
     {
       struct target_waitstatus status;
 
-      ops->wait (minus_one_ptid, &status, 0);
+      last_ptid = this->wait (minus_one_ptid, &status, 0);
 
       /* Note windows_wait returns TARGET_WAITKIND_SPURIOUS for thread
         events.  */
@@ -2164,9 +2037,11 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
          && status.kind != TARGET_WAITKIND_SPURIOUS)
        break;
 
-      ops->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
+      this->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
     }
 
+  switch_to_thread (find_thread_ptid (this, last_ptid));
+
   /* Now that the inferior has been started and all DLLs have been mapped,
      we can iterate over all DLLs and load them in.
 
@@ -2298,7 +2173,7 @@ windows_nat_target::attach (const char *args, int from_tty)
     }
 #endif
 
-  do_initial_windows_stuff (this, pid, 1);
+  do_initial_windows_stuff (pid, 1);
   target_terminal::ours ();
 }
 
@@ -2328,7 +2203,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
     }
 
   x86_cleanup_dregs ();
-  inferior_ptid = null_ptid;
+  switch_to_no_thread ();
   detach_inferior (inf);
 
   maybe_unpush_target ();
@@ -2855,7 +2730,7 @@ windows_nat_target::create_inferior (const char *exec_file,
   PROCESS_INFORMATION pi;
   BOOL ret;
   DWORD flags = 0;
-  const char *inferior_io_terminal = get_inferior_io_terminal ();
+  const char *inferior_tty = current_inferior ()->tty ();
 
   if (!exec_file)
     error (_("No executable specified, use `target exec'."));
@@ -2954,14 +2829,14 @@ windows_nat_target::create_inferior (const char *exec_file,
       w32_env = NULL;
     }
 
-  if (!inferior_io_terminal)
+  if (inferior_tty == nullptr)
     tty = ostdin = ostdout = ostderr = -1;
   else
     {
-      tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY);
+      tty = open (inferior_tty, O_RDWR | O_NOCTTY);
       if (tty < 0)
        {
-         print_sys_errmsg (inferior_io_terminal, errno);
+         print_sys_errmsg (inferior_tty, errno);
          ostdin = ostdout = ostderr = -1;
        }
       else
@@ -3026,19 +2901,19 @@ windows_nat_target::create_inferior (const char *exec_file,
       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
+     line, use INFERIOR_TTY for those which aren't.  */
+  if (inferior_tty != nullptr
       && !(fd_inp >= 0 && fd_out >= 0 && fd_err >= 0))
     {
       SECURITY_ATTRIBUTES sa;
       sa.nLength = sizeof(sa);
       sa.lpSecurityDescriptor = 0;
       sa.bInheritHandle = TRUE;
-      tty = CreateFileA (inferior_io_terminal, GENERIC_READ | GENERIC_WRITE,
+      tty = CreateFileA (inferior_tty, GENERIC_READ | GENERIC_WRITE,
                         0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
       if (tty == INVALID_HANDLE_VALUE)
        warning (_("Warning: Failed to open TTY %s, error %#x."),
-                inferior_io_terminal, (unsigned) GetLastError ());
+                inferior_tty, (unsigned) GetLastError ());
     }
   if (redirected || tty != INVALID_HANDLE_VALUE)
     {
@@ -3138,7 +3013,7 @@ windows_nat_target::create_inferior (const char *exec_file,
   else
     saw_create = 0;
 
-  do_initial_windows_stuff (this, pi.dwProcessId, 0);
+  do_initial_windows_stuff (pi.dwProcessId, 0);
 
   /* windows_continue (DBG_CONTINUE, -1, 0); */
 }
@@ -3217,7 +3092,7 @@ windows_nat_target::kill ()
     {
       if (!windows_continue (DBG_CONTINUE, -1, 1))
        break;
-      if (!WaitForDebugEvent (&current_event, INFINITE))
+      if (!wait_for_debug_event (&current_event, INFINITE))
        break;
       if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
        break;
@@ -3372,7 +3247,7 @@ windows_nat_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
 {
   windows_thread_info *th;
 
-  th = thread_rec (ptid.lwp (), DONT_INVALIDATE_CONTEXT);
+  th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
   if (th == NULL)
     return false;
 
@@ -3393,7 +3268,7 @@ windows_nat_target::get_ada_task_ptid (long lwp, long thread)
 const char *
 windows_nat_target::thread_name (struct thread_info *thr)
 {
-  return thread_rec (thr->ptid.lwp (), DONT_INVALIDATE_CONTEXT)->name.get ();
+  return thread_rec (thr->ptid, DONT_INVALIDATE_CONTEXT)->name.get ();
 }
 
 
@@ -3552,12 +3427,9 @@ cygwin_get_dr7 (void)
 bool
 windows_nat_target::thread_alive (ptid_t ptid)
 {
-  int tid;
-
   gdb_assert (ptid.lwp () != 0);
-  tid = ptid.lwp ();
 
-  return (WaitForSingleObject (thread_rec (tid, DONT_INVALIDATE_CONTEXT)->h, 0)
+  return (WaitForSingleObject (thread_rec (ptid, DONT_INVALIDATE_CONTEXT)->h, 0)
          != WAIT_OBJECT_0);
 }
 
This page took 0.041996 seconds and 4 git commands to generate.