gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / windows-nat.c
index d04dc06f3bf7cd7bfd31f0addff2827f0af05729..3452f6c827f45bc40361bbf72d97d911eac4823c 100644 (file)
@@ -217,10 +217,10 @@ static int windows_initialization_done;
 #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);
@@ -235,7 +235,6 @@ 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.  */
@@ -605,6 +604,7 @@ windows_fetch_one_register (struct regcache *regcache,
   else
     {
       if (th->stopped_at_software_breakpoint
+         && !th->pc_adjusted
          && r == gdbarch_pc_regnum (gdbarch))
        {
          int size = register_size (gdbarch, r);
@@ -623,6 +623,8 @@ windows_fetch_one_register (struct regcache *regcache,
              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);
     }
@@ -821,7 +823,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);
@@ -829,7 +834,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;
@@ -1228,6 +1233,31 @@ windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
   return false;
 }
 
+/* See nat/windows-nat.h.  */
+
+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
    threads, if we are continuing execution.  KILLED non-zero means we
    have killed the inferior, so we should ignore weird errors due to
@@ -1495,17 +1525,6 @@ ctrl_c_handler (DWORD event_type)
   return TRUE;
 }
 
-/* A wrapper for WaitForDebugEvent that sets "last_wait_event"
-   appropriately.  */
-static BOOL
-wait_for_debug_event (DEBUG_EVENT *event, DWORD timeout)
-{
-  BOOL result = WaitForDebugEvent (event, timeout);
-  if (result)
-    last_wait_event = *event;
-  return result;
-}
-
 /* Get the next event from the child.  Returns a non-zero thread id if the event
    requires handling by WFI (or whatever).  */
 
@@ -1522,29 +1541,18 @@ windows_nat_target::get_windows_debug_event (int pid,
   /* 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.  */
-  for (auto iter = pending_stops.begin ();
-       iter != pending_stops.end ();
-       ++iter)
+  gdb::optional<pending_stop> stop = fetch_pending_stop (debug_events);
+  if (stop.has_value ())
     {
-      if (desired_stop_thread_id == -1
-         || desired_stop_thread_id == iter->thread_id)
-       {
-         thread_id = iter->thread_id;
-         *ourstatus = iter->status;
-         current_event = iter->event;
+      thread_id = stop->thread_id;
+      *ourstatus = stop->status;
 
-         inferior_ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
-         current_windows_thread = thread_rec (inferior_ptid,
-                                              INVALIDATE_CONTEXT);
-         current_windows_thread->reload_context = 1;
-
-         DEBUG_EVENTS (("get_windows_debug_event - "
-                        "pending stop found in 0x%x (desired=0x%x)\n",
-                        thread_id, desired_stop_thread_id));
+      inferior_ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
+      current_windows_thread = thread_rec (inferior_ptid,
+                                          INVALIDATE_CONTEXT);
+      current_windows_thread->reload_context = 1;
 
-         pending_stops.erase (iter);
-         return thread_id;
-       }
+      return thread_id;
     }
 
   last_sig = GDB_SIGNAL_0;
@@ -1743,13 +1751,16 @@ windows_nat_target::get_windows_debug_event (int pid,
                     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
+              == 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);
          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;
@@ -1823,10 +1834,16 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
            {
              current_windows_thread->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
+                      == EXCEPTION_BREAKPOINT)
+                     || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+                         == STATUS_WX86_BREAKPOINT))
                  && windows_initialization_done)
-               current_windows_thread->stopped_at_software_breakpoint = true;
+               {
+                 current_windows_thread->stopped_at_software_breakpoint
+                   = true;
+                 current_windows_thread->pc_adjusted = false;
+               }
            }
 
          return result;
This page took 0.032404 seconds and 4 git commands to generate.