gdb: restore displaced step buffer bytes when another thread forks
authorSimon Marchi <simon.marchi@polymtl.ca>
Fri, 4 Dec 2020 21:43:52 +0000 (16:43 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Fri, 4 Dec 2020 21:43:52 +0000 (16:43 -0500)
In handle_inferior_event, where we handle forks, we make sure to restore
the bytes of the displaced stepping buffer in the child's address
space.  However, we only do it when the forking thread was the one
doing a displaced step.  It could happen that a thread forks while
another one is doing a displaced step.  In this case, we also need to
restore the bytes in the child.

Move the byte-restoring code outside of the condition that checks
whether the event thread was displaced stepping.

gdb/ChangeLog:

* infrun.c (handle_inferior_event): Restore displaced step
buffer bytes in child process when handling fork, even if fork
happened in another thread than the displaced-stepping one.

Change-Id: Ibb0daaeb123aba03f4fb4b4d820754eb2436bc69

gdb/ChangeLog
gdb/infrun.c

index 8ce239f4b35237027a22590b36d1527b12aab641..f977321f15e5ec29103988d69e2cdba99c3941d7 100644 (file)
@@ -1,3 +1,9 @@
+2020-12-04  Simon Marchi  <simon.marchi@polymtl.ca>
+
+       * infrun.c (handle_inferior_event): Restore displaced step
+       buffer bytes in child process when handling fork, even if fork
+       happened in another thread than the displaced-stepping one.
+
 2020-12-04  Simon Marchi  <simon.marchi@efficios.com>
 
        * infrun.c (infrun_inferior_execd): New function.
index 0e0a7a691c437cee61a05942deefeba05a1d4d73..5c383b4d8a12da81fbcddc57003a92dd30db7886 100644 (file)
@@ -5302,25 +5302,27 @@ handle_inferior_event (struct execution_control_state *ecs)
       {
        struct regcache *regcache = get_thread_regcache (ecs->event_thread);
        struct gdbarch *gdbarch = regcache->arch ();
+       inferior *parent_inf = find_inferior_ptid (ecs->target, ecs->ptid);
 
-       /* If checking displaced stepping is supported, and thread
-          ecs->ptid is displaced stepping.  */
+       /* If this is a fork (child gets its own address space copy) and the
+          displaced step buffer was in use at the time of the fork, restore
+          displaced step buffer bytes in the child process.  */
+       if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
+         {
+           displaced_step_inferior_state *displaced
+             = get_displaced_stepping_state (parent_inf);
+
+           if (displaced->step_thread != nullptr)
+             displaced_step_restore (displaced, ecs->ws.value.related_pid);
+         }
+
+       /* If displaced stepping is supported, and thread ecs->ptid is
+          displaced stepping.  */
        if (displaced_step_in_progress_thread (ecs->event_thread))
          {
-           struct inferior *parent_inf
-             = find_inferior_ptid (ecs->target, ecs->ptid);
            struct regcache *child_regcache;
            CORE_ADDR parent_pc;
 
-           if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
-             {
-               struct displaced_step_inferior_state *displaced
-                 = get_displaced_stepping_state (parent_inf);
-
-               /* Restore scratch pad for child process.  */
-               displaced_step_restore (displaced, ecs->ws.value.related_pid);
-             }
-
            /* GDB has got TARGET_WAITKIND_FORKED or TARGET_WAITKIND_VFORKED,
               indicating that the displaced stepping of syscall instruction
               has been done.  Perform cleanup for parent process here.  Note