Implement stopped_by_sw_breakpoint for Windows gdbserver
authorTom Tromey <tromey@adacore.com>
Wed, 8 Apr 2020 20:33:35 +0000 (14:33 -0600)
committerTom Tromey <tromey@adacore.com>
Wed, 8 Apr 2020 20:47:59 +0000 (14:47 -0600)
This changes the Windows gdbserver port to implement the
stopped_by_sw_breakpoint target method.  This is needed to support
pending stops.

This is a separate patch now, because Pedro suggested splitting it out
for simpler bisecting, in the case that it introduces a bug.

gdbserver/ChangeLog
2020-04-08  Tom Tromey  <tromey@adacore.com>

* win32-low.h  (win32_process_target::stopped_by_sw_breakpoint)
(win32_process_target::supports_stopped_by_sw_breakpoint):
Declare.
* win32-low.c (win32_supports_z_point_type): Always handle
Z_PACKET_SW_BP.
(win32_insert_point): Call insert_memory_breakpoint when needed.
(win32_remove_point): Call remove_memory_breakpoint when needed.
(win32_process_target::stopped_by_sw_breakpoint)
(win32_process_target::supports_stopped_by_sw_breakpoint): New
methods.
(win32_target_ops): Update.
(maybe_adjust_pc): New function.
(win32_wait): Call maybe_adjust_pc.

gdbserver/ChangeLog
gdbserver/win32-low.cc
gdbserver/win32-low.h

index 24c42e28d06c9aa027f05eeca15e8d8148021f04..36d6f29e424400067bbdb8d27919ab09d3e054cc 100644 (file)
@@ -1,3 +1,19 @@
+2020-04-08  Tom Tromey  <tromey@adacore.com>
+
+       * win32-low.h  (win32_process_target::stopped_by_sw_breakpoint)
+       (win32_process_target::supports_stopped_by_sw_breakpoint):
+       Declare.
+       * win32-low.c (win32_supports_z_point_type): Always handle
+       Z_PACKET_SW_BP.
+       (win32_insert_point): Call insert_memory_breakpoint when needed.
+       (win32_remove_point): Call remove_memory_breakpoint when needed.
+       (win32_process_target::stopped_by_sw_breakpoint)
+       (win32_process_target::supports_stopped_by_sw_breakpoint): New
+       methods.
+       (win32_target_ops): Update.
+       (maybe_adjust_pc): New function.
+       (win32_wait): Call maybe_adjust_pc.
+
 2020-04-08  Tom Tromey  <tromey@adacore.com>
 
        * win32-low.h (struct win32_target_ops) <decr_pc_after_break>: New
index 131eacb13c4110e7eb22a36d174f1147ebf10101..4312bb3ab7cc3a8bb988febf680a09c5cb227ac8 100644 (file)
@@ -236,15 +236,18 @@ child_delete_thread (DWORD pid, DWORD tid)
 bool
 win32_process_target::supports_z_point_type (char z_type)
 {
-  return (the_low_target.supports_z_point_type != NULL
-         && the_low_target.supports_z_point_type (z_type));
+  return (z_type == Z_PACKET_SW_BP
+         || (the_low_target.supports_z_point_type != NULL
+             && the_low_target.supports_z_point_type (z_type)));
 }
 
 int
 win32_process_target::insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
                                    int size, raw_breakpoint *bp)
 {
-  if (the_low_target.insert_point != NULL)
+  if (type == raw_bkpt_type_sw)
+    return insert_memory_breakpoint (bp);
+  else if (the_low_target.insert_point != NULL)
     return the_low_target.insert_point (type, addr, size, bp);
   else
     /* Unsupported (see target.h).  */
@@ -255,7 +258,9 @@ int
 win32_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
                                    int size, raw_breakpoint *bp)
 {
-  if (the_low_target.remove_point != NULL)
+  if (type == raw_bkpt_type_sw)
+    return remove_memory_breakpoint (bp);
+  else if (the_low_target.remove_point != NULL)
     return the_low_target.remove_point (type, addr, size, bp);
   else
     /* Unsupported (see target.h).  */
@@ -1189,6 +1194,32 @@ windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
   return false;
 }
 
+/* A helper function that will, if needed, set
+   'stopped_at_software_breakpoint' on the thread and adjust the
+   PC.  */
+
+static void
+maybe_adjust_pc ()
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 1);
+  child_fetch_inferior_registers (regcache, -1);
+
+  windows_thread_info *th = thread_rec (current_thread_ptid (),
+                                       DONT_INVALIDATE_CONTEXT);
+  th->stopped_at_software_breakpoint = false;
+
+  if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+      && (current_event.u.Exception.ExceptionRecord.ExceptionCode
+         == EXCEPTION_BREAKPOINT)
+      && child_initialization_done)
+    {
+      th->stopped_at_software_breakpoint = true;
+      CORE_ADDR pc = regcache_read_pc (regcache);
+      CORE_ADDR sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break;
+      regcache_write_pc (regcache, sw_breakpoint_pc);
+    }
+}
+
 /* Get the next event from the child.  */
 
 static int
@@ -1417,8 +1448,6 @@ ptid_t
 win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
                            int options)
 {
-  struct regcache *regcache;
-
   if (cached_status.kind != TARGET_WAITKIND_IGNORE)
     {
       /* The core always does a wait after creating the inferior, and
@@ -1446,12 +1475,12 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
        case TARGET_WAITKIND_STOPPED:
        case TARGET_WAITKIND_SIGNALLED:
        case TARGET_WAITKIND_LOADED:
-         OUTMSG2 (("Child Stopped with signal = %d \n",
-                   ourstatus->value.sig));
-
-         regcache = get_thread_regcache (current_thread, 1);
-         child_fetch_inferior_registers (regcache, -1);
-         return debug_event_ptid (&current_event);
+         {
+           OUTMSG2 (("Child Stopped with signal = %d \n",
+                     ourstatus->value.sig));
+           maybe_adjust_pc ();
+           return debug_event_ptid (&current_event);
+         }
        default:
          OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
          /* fall-through */
@@ -1659,6 +1688,20 @@ win32_process_target::sw_breakpoint_from_kind (int kind, int *size)
   return the_low_target.breakpoint;
 }
 
+bool
+win32_process_target::stopped_by_sw_breakpoint ()
+{
+  windows_thread_info *th = thread_rec (current_thread_ptid (),
+                                       DONT_INVALIDATE_CONTEXT);
+  return th == nullptr ? false : th->stopped_at_software_breakpoint;
+}
+
+bool
+win32_process_target::supports_stopped_by_sw_breakpoint ()
+{
+  return true;
+}
+
 CORE_ADDR
 win32_process_target::read_pc (struct regcache *regcache)
 {
index d2b39a46fd90943c9fa070687a2a76f23e01ef24..b3fa392dd31597437563c25cf7c89d7827ccd672 100644 (file)
@@ -155,6 +155,10 @@ public:
   CORE_ADDR read_pc (regcache *regcache) override;
 
   void write_pc (regcache *regcache, CORE_ADDR pc) override;
+
+  bool stopped_by_sw_breakpoint () override;
+
+  bool supports_stopped_by_sw_breakpoint () override;
 };
 
 /* Retrieve the context for this thread, if not already retrieved.  */