aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog9
-rw-r--r--gdb/infrun.c83
-rw-r--r--gdb/regcache.c30
-rw-r--r--gdb/regcache.h3
4 files changed, 103 insertions, 22 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 491e33d..a79dd02 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/infrun.c b/gdb/infrun.c
index c72b05d..9a2de5c 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -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);
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 0af93e8..37092f8 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -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;
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 7f7dc10..5531f39 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -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);