* 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.
This commit is contained in:
Yao Qi 2011-09-17 13:29:32 +00:00
parent 53dad163f7
commit e2d966398c
4 changed files with 103 additions and 22 deletions

View 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

View 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);

View 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;

View 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);