diff options
author | Yao Qi <yao@codesourcery.com> | 2011-09-17 13:29:32 +0000 |
---|---|---|
committer | Yao Qi <yao@codesourcery.com> | 2011-09-17 13:29:32 +0000 |
commit | e2d966398c7963a6448f0d3d4451438efeda66e7 (patch) | |
tree | f4cea31c1bc6332c67f63b99309b55361bae82c7 /gdb/infrun.c | |
parent | 53dad163f707be6f386ca506b86e195b747d7169 (diff) | |
download | gdb-e2d966398c7963a6448f0d3d4451438efeda66e7.zip gdb-e2d966398c7963a6448f0d3d4451438efeda66e7.tar.gz gdb-e2d966398c7963a6448f0d3d4451438efeda66e7.tar.bz2 |
gdb/
* 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.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r-- | gdb/infrun.c | 83 |
1 files changed, 72 insertions, 11 deletions
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); |