gdb/
authorYao Qi <yao@codesourcery.com>
Sat, 17 Sep 2011 13:29:32 +0000 (13:29 +0000)
committerYao Qi <yao@codesourcery.com>
Sat, 17 Sep 2011 13:29:32 +0000 (13:29 +0000)
* infrun.c (displaced_step_fixup): Move some code ...
(displaced_step_restore): ... here.  New function.
(handle_inferior_event): Cleanup displaced stepping state for both
child and parent when get forked or vforked event.
* regcache.c (get_thread_arch_aspace_regcache): New function.
get_thread_arch_regcache (): Call it.

gdb/ChangeLog
gdb/infrun.c
gdb/regcache.c
gdb/regcache.h

index 491e33d857a30d759d4f80554893bbcfae4dc529..a79dd0233152a1a2cc514f18dbc02459da409908 100644 (file)
@@ -1,3 +1,12 @@
+2011-09-17  Yao Qi  <yao@codesourcery.com>
+
+       * infrun.c (displaced_step_fixup): Move some code ...
+       (displaced_step_restore): ... here.  New function.
+       (handle_inferior_event): Cleanup displaced stepping state for both
+       child and parent when get forked or vforked event.
+       * regcache.c (get_thread_arch_aspace_regcache): New function.
+       get_thread_arch_regcache (): Call it.
+
 2011-09-16  Joel Brobecker  <brobecker@adacore.com>
 
        * ada-tasks.c (print_ada_task_info): New function, merging
index c72b05dbe002169d7a35a3f760addeae96ee9939..9a2de5ca6a732d9595956bb321a7816b20bc040b 100644 (file)
@@ -1364,6 +1364,23 @@ write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr,
   do_cleanups (ptid_cleanup);
 }
 
+/* Restore the contents of the copy area for thread PTID.  */
+
+static void
+displaced_step_restore (struct displaced_step_inferior_state *displaced,
+                       ptid_t ptid)
+{
+  ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch);
+
+  write_memory_ptid (ptid, displaced->step_copy,
+                    displaced->step_saved_copy, len);
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: restored %s %s\n",
+                       target_pid_to_str (ptid),
+                       paddress (displaced->step_gdbarch,
+                                 displaced->step_copy));
+}
+
 static void
 displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
 {
@@ -1382,17 +1399,7 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
 
   old_cleanups = make_cleanup (displaced_step_clear_cleanup, displaced);
 
-  /* Restore the contents of the copy area.  */
-  {
-    ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch);
-
-    write_memory_ptid (displaced->step_ptid, displaced->step_copy,
-                      displaced->step_saved_copy, len);
-    if (debug_displaced)
-      fprintf_unfiltered (gdb_stdlog, "displaced: restored %s\n",
-                          paddress (displaced->step_gdbarch,
-                                   displaced->step_copy));
-  }
+  displaced_step_restore (displaced, displaced->step_ptid);
 
   /* Did the instruction complete successfully?  */
   if (signal == TARGET_SIGNAL_TRAP)
@@ -3373,6 +3380,60 @@ handle_inferior_event (struct execution_control_state *ecs)
       if (debug_infrun)
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_FORKED\n");
 
+      /* Check whether the inferior is displaced stepping.  */
+      {
+       struct regcache *regcache = get_thread_regcache (ecs->ptid);
+       struct gdbarch *gdbarch = get_regcache_arch (regcache);
+       struct displaced_step_inferior_state *displaced
+         = get_displaced_stepping_state (ptid_get_pid (ecs->ptid));
+
+       /* If checking displaced stepping is supported, and thread
+          ecs->ptid is displaced stepping.  */
+       if (displaced && ptid_equal (displaced->step_ptid, ecs->ptid))
+         {
+           struct inferior *parent_inf
+             = find_inferior_pid (ptid_get_pid (ecs->ptid));
+           struct regcache *child_regcache;
+           CORE_ADDR parent_pc;
+
+           /* 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
+              that this operation also cleans up the child process for vfork,
+              because their pages are shared.  */
+           displaced_step_fixup (ecs->ptid, TARGET_SIGNAL_TRAP);
+
+           if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
+             {
+               /* Restore scratch pad for child process.  */
+               displaced_step_restore (displaced, ecs->ws.value.related_pid);
+             }
+
+           /* Since the vfork/fork syscall instruction was executed in the scratchpad,
+              the child's PC is also within the scratchpad.  Set the child's PC
+              to the parent's PC value, which has already been fixed up.
+              FIXME: we use the parent's aspace here, although we're touching
+              the child, because the child hasn't been added to the inferior
+              list yet at this point.  */
+
+           child_regcache
+             = get_thread_arch_aspace_regcache (ecs->ws.value.related_pid,
+                                                gdbarch,
+                                                parent_inf->aspace);
+           /* Read PC value of parent process.  */
+           parent_pc = regcache_read_pc (regcache);
+
+           if (debug_displaced)
+             fprintf_unfiltered (gdb_stdlog,
+                                 "displaced: write child pc from %s to %s\n",
+                                 paddress (gdbarch,
+                                           regcache_read_pc (child_regcache)),
+                                 paddress (gdbarch, parent_pc));
+
+           regcache_write_pc (child_regcache, parent_pc);
+         }
+      }
+
       if (!ptid_equal (ecs->ptid, inferior_ptid))
        {
          context_switch (ecs->ptid);
index 0af93e83a4148dabd0fa0c5eb3439ddb561f6983..37092f825514ecd042226ec165daa5cf86112327 100644 (file)
@@ -450,17 +450,33 @@ struct regcache_list
 static struct regcache_list *current_regcache;
 
 struct regcache *
-get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
+                                struct address_space *aspace)
 {
   struct regcache_list *list;
   struct regcache *new_regcache;
-  struct address_space *aspace;
 
   for (list = current_regcache; list; list = list->next)
     if (ptid_equal (list->regcache->ptid, ptid)
        && get_regcache_arch (list->regcache) == gdbarch)
       return list->regcache;
 
+  new_regcache = regcache_xmalloc_1 (gdbarch, aspace, 0);
+  new_regcache->ptid = ptid;
+
+  list = xmalloc (sizeof (struct regcache_list));
+  list->regcache = new_regcache;
+  list->next = current_regcache;
+  current_regcache = list;
+
+  return new_regcache;
+}
+
+struct regcache *
+get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+{
+  struct address_space *aspace;
+
   /* For the benefit of "maint print registers" & co when debugging an
      executable, allow dumping the regcache even when there is no
      thread selected (target_thread_address_space internal-errors if
@@ -471,15 +487,7 @@ get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
            ? NULL
            : target_thread_address_space (ptid));
 
-  new_regcache = regcache_xmalloc_1 (gdbarch, aspace, 0);
-  new_regcache->ptid = ptid;
-
-  list = xmalloc (sizeof (struct regcache_list));
-  list->regcache = new_regcache;
-  list->next = current_regcache;
-  current_regcache = list;
-
-  return new_regcache;
+  return get_thread_arch_aspace_regcache  (ptid, gdbarch, aspace);
 }
 
 static ptid_t current_thread_ptid;
index 7f7dc105968001a03c19e9aac7e2dc5607a9818c..5531f398cae07be73be5e7c2eba746afd43eb7b0 100644 (file)
@@ -28,6 +28,9 @@ struct address_space;
 extern struct regcache *get_current_regcache (void);
 extern struct regcache *get_thread_regcache (ptid_t ptid);
 extern struct regcache *get_thread_arch_regcache (ptid_t, struct gdbarch *);
+extern struct regcache *get_thread_arch_aspace_regcache (ptid_t,
+                                                        struct gdbarch *,
+                                                        struct address_space *);
 
 void regcache_xfree (struct regcache *regcache);
 struct cleanup *make_cleanup_regcache_xfree (struct regcache *regcache);