Remove context switching in favour of accessing thread_info fields

directly.

	* infrun.c (stepping_over_breakpoint, step_resume_breakpoint):
	Delete.
	(struct thread_stepping_state): Delete.
	(gtss, tss): Delete.
	(follow_inferior_reset_breakpoints, follow_exec)
	(resume, clear_proceed_status): Adjust.
	(prev_pc): Delete.
	(proceed, start_remote, init_wait_for_inferior): Adjust.
	(struct execution_control_state): Add event_thread member.
	(delete_step_resume_breakpoint_callback)
	(delete_step_thread_step_resume_breakpoint)
	(delete_step_thread_step_resume_breakpoint_cleanup)
	(delete_step_thread_step_resume_breakpoint): New.
	(wait_for_inferior, init_execution_control_state): Use
	delete_step_thread_step_resume_breakpoint_cleanup.
	(wait_for_inferior): Set the event_thread.
	(fetch_inferior_event): Ditto.  Delete the step-resume breakpoint
	with delete_step_thread_step_resume_breakpoint.
	(init_thread_stepping_state): Change parameter type to
	thread_info.  Adjust.
	(context_switch): Don't context switch prev_pc,
	stepping_over_breakpoint, step_resume_breakpoint,
	step_range_start, step_range_end, step_frame_id,
	tss->stepping_over_breakpoint,
	tss->stepping_through_solib_after_catch,
	tss->stepping_through_solib_catchpoints, tss->current_line, or
	tss->current_symtab.
	(adjust_pc_after_break, handle_inferior_event)
	(currently_stepping, step_into_function)
	(insert_step_resume_breakpoint_at_sal)
	(insert_longjmp_resume_breakpoint, keep_going): Adjust.
	(clear_stepping_state): New.
	(normal_stop): Adjust.
	(save_inferior_status, restore_inferior_status): Adjust.

	* gdbthread.h (struct thread_info): Comments describing the
	members moved here.  Add step_after_step_resume_breakpoint.
	(delete_step_resume_breakpoint): Add thread_info argument.
	(save_infrun_state, load_infrun_state): Remove prev_pc,
	trap_expected, step_resume_breakpoint, step_range_start,
	step_range_end, step_frame_id, another_trap,
	stepping_through_solib_after_catch,
	stepping_through_solib_catchpoints, current_line and
	current_symtab function arguments.
	(inferior_thread): Declare.

	* thread.c (inferior_thread): New.
	(delete_step_resume_breakpoint): Add a thread_info parameter and
	rewrite.
	(load_infrun_state, save_infrun_state): Remove prev_pc,
	trap_expected, step_resume_breakpoint, step_range_start,
	step_range_end, step_frame_id, stepping_over_breakpoint,
	stepping_through_solib_after_catch,
	stepping_through_solib_catchpoints, current_line and
	current_symtab args.  Remove code referencing them.

	* infcmd.c (step_range_start, step_range_end, step_frame_id):
	Delete.
	(step_1, step_once, until_next_command): Adjust.

	* inferior.h (step_range_start, step_range_end, step_frame_id):
	Delete.

	* linux-nat.c (linux_child_follow_fork): If following the child,
	move the step state to it.  Adjust.
	* inf-ptrace.c (inf_ptrace_follow_fork): Ditto.
	* inf-ttrace.c (inf_ttrace_follow_fork): Ditto.
This commit is contained in:
Pedro Alves 2008-09-08 21:40:39 +00:00
parent 757f359dd1
commit 4e1c45eac7
9 changed files with 438 additions and 344 deletions

View file

@ -1,3 +1,76 @@
2008-09-08 Pedro Alves <pedro@codesourcery.com>
Remove context switching in favour of accessing thread_info fields
directly.
* infrun.c (stepping_over_breakpoint, step_resume_breakpoint):
Delete.
(struct thread_stepping_state): Delete.
(gtss, tss): Delete.
(follow_inferior_reset_breakpoints, follow_exec)
(resume, clear_proceed_status): Adjust.
(prev_pc): Delete.
(proceed, start_remote, init_wait_for_inferior): Adjust.
(struct execution_control_state): Add event_thread member.
(delete_step_resume_breakpoint_callback)
(delete_step_thread_step_resume_breakpoint)
(delete_step_thread_step_resume_breakpoint_cleanup)
(delete_step_thread_step_resume_breakpoint): New.
(wait_for_inferior, init_execution_control_state): Use
delete_step_thread_step_resume_breakpoint_cleanup.
(wait_for_inferior): Set the event_thread.
(fetch_inferior_event): Ditto. Delete the step-resume breakpoint
with delete_step_thread_step_resume_breakpoint.
(init_thread_stepping_state): Change parameter type to
thread_info. Adjust.
(context_switch): Don't context switch prev_pc,
stepping_over_breakpoint, step_resume_breakpoint,
step_range_start, step_range_end, step_frame_id,
tss->stepping_over_breakpoint,
tss->stepping_through_solib_after_catch,
tss->stepping_through_solib_catchpoints, tss->current_line, or
tss->current_symtab.
(adjust_pc_after_break, handle_inferior_event)
(currently_stepping, step_into_function)
(insert_step_resume_breakpoint_at_sal)
(insert_longjmp_resume_breakpoint, keep_going): Adjust.
(clear_stepping_state): New.
(normal_stop): Adjust.
(save_inferior_status, restore_inferior_status): Adjust.
* gdbthread.h (struct thread_info): Comments describing the
members moved here. Add step_after_step_resume_breakpoint.
(delete_step_resume_breakpoint): Add thread_info argument.
(save_infrun_state, load_infrun_state): Remove prev_pc,
trap_expected, step_resume_breakpoint, step_range_start,
step_range_end, step_frame_id, another_trap,
stepping_through_solib_after_catch,
stepping_through_solib_catchpoints, current_line and
current_symtab function arguments.
(inferior_thread): Declare.
* thread.c (inferior_thread): New.
(delete_step_resume_breakpoint): Add a thread_info parameter and
rewrite.
(load_infrun_state, save_infrun_state): Remove prev_pc,
trap_expected, step_resume_breakpoint, step_range_start,
step_range_end, step_frame_id, stepping_over_breakpoint,
stepping_through_solib_after_catch,
stepping_through_solib_catchpoints, current_line and
current_symtab args. Remove code referencing them.
* infcmd.c (step_range_start, step_range_end, step_frame_id):
Delete.
(step_1, step_once, until_next_command): Adjust.
* inferior.h (step_range_start, step_range_end, step_frame_id):
Delete.
* linux-nat.c (linux_child_follow_fork): If following the child,
move the step state to it. Adjust.
* inf-ptrace.c (inf_ptrace_follow_fork): Ditto.
* inf-ttrace.c (inf_ttrace_follow_fork): Ditto.
2008-09-08 Pedro Alves <pedro@codesourcery.com>
* bsd-uthread.c (bsd_uthread_find_new_threads): Claim the main

View file

@ -61,17 +61,70 @@ struct thread_info
if we detect it exiting. */
int refcount;
/* State from wait_for_inferior */
CORE_ADDR prev_pc;
/* User/external stepping state. */
/* Step-resume or longjmp-resume breakpoint. */
struct breakpoint *step_resume_breakpoint;
CORE_ADDR step_range_start;
CORE_ADDR step_range_end;
/* Range to single step within.
If this is nonzero, respond to a single-step signal by continuing
to step if the pc is in this range.
If step_range_start and step_range_end are both 1, it means to
step for a single instruction (FIXME: it might clean up
wait_for_inferior in a minor way if this were changed to the
address of the instruction and that address plus one. But maybe
not.). */
CORE_ADDR step_range_start; /* Inclusive */
CORE_ADDR step_range_end; /* Exclusive */
/* Stack frame address as of when stepping command was issued.
This is how we know when we step into a subroutine call, and how
to set the frame for the breakpoint used to step out. */
struct frame_id step_frame_id;
int current_line;
struct symtab *current_symtab;
/* Internal stepping state. */
/* Record the pc of the thread the last time it stopped. This is
maintained by proceed and keep_going, and used in
adjust_pc_after_break to distinguish a hardware single-step
SIGTRAP from a breakpoint SIGTRAP. */
CORE_ADDR prev_pc;
/* Nonzero if we are presently stepping over a breakpoint.
If we hit a breakpoint or watchpoint, and then continue, we need
to single step the current thread with breakpoints disabled, to
avoid hitting the same breakpoint or watchpoint again. And we
should step just a single thread and keep other threads stopped,
so that other threads don't miss breakpoints while they are
removed.
So, this variable simultaneously means that we need to single
step the current thread, keep other threads stopped, and that
breakpoints should be removed while we step.
This variable is set either:
- in proceed, when we resume inferior on user's explicit request
- in keep_going, if handle_inferior_event decides we need to
step over breakpoint.
The variable is cleared in normal_stop. The proceed calls
wait_for_inferior, which calls handle_inferior_event in a loop,
and until wait_for_inferior exits, this variable is changed only
by keep_going. */
int trap_expected;
/* Should we step over breakpoint next time keep_going is called? */
int stepping_over_breakpoint;
/* Set to TRUE if we should finish single-stepping over a breakpoint
after hitting the current step-resume breakpoint. */
int step_after_step_resume_breakpoint;
/* This is set TRUE when a catchpoint of a shared library event
triggers. Since we don't wish to leave the inferior in the
solib hook when we report the event, we step the inferior
@ -127,7 +180,7 @@ extern void delete_thread (ptid_t);
extern void delete_thread_silent (ptid_t);
/* Delete a step_resume_breakpoint from the thread database. */
extern void delete_step_resume_breakpoint (void *);
extern void delete_step_resume_breakpoint (struct thread_info *);
/* Translate the integer thread id (GDB's homegrown id, not the system's)
into a "pid" (which may be overloaded with extra thread information). */
@ -163,17 +216,6 @@ extern int thread_count (void);
/* infrun context switch: save the debugger state for the given thread. */
extern void save_infrun_state (ptid_t ptid,
CORE_ADDR prev_pc,
int trap_expected,
struct breakpoint *step_resume_breakpoint,
CORE_ADDR step_range_start,
CORE_ADDR step_range_end,
const struct frame_id *step_frame_id,
int another_trap,
int stepping_through_solib_after_catch,
bpstat stepping_through_solib_catchpoints,
int current_line,
struct symtab *current_symtab,
struct continuation *continuations,
struct continuation *intermediate_continuations,
int proceed_to_finish,
@ -186,17 +228,6 @@ extern void save_infrun_state (ptid_t ptid,
/* infrun context switch: load the debugger state previously saved
for the given thread. */
extern void load_infrun_state (ptid_t ptid,
CORE_ADDR *prev_pc,
int *trap_expected,
struct breakpoint **step_resume_breakpoint,
CORE_ADDR *step_range_start,
CORE_ADDR *step_range_end,
struct frame_id *step_frame_id,
int *another_trap,
int *stepping_through_solib_after_catch,
bpstat *stepping_through_solib_catchpoints,
int *current_line,
struct symtab **current_symtab,
struct continuation **continuations,
struct continuation **intermediate_continuations,
int *proceed_to_finish,
@ -263,5 +294,8 @@ extern void print_thread_info (struct ui_out *uiout, int thread);
extern struct cleanup *make_cleanup_restore_current_thread (void);
/* Returns a pointer into the thread_info corresponding to
INFERIOR_PTID. INFERIOR_PTID *must* be in the thread list. */
extern struct thread_info* inferior_thread (void);
#endif /* GDBTHREAD_H */

View file

@ -46,6 +46,7 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
{
pid_t pid, fpid;
ptrace_state_t pe;
struct thread_info *last_tp = NULL;
/* FIXME: kettenis/20050720: This stuff should really be passed as
an argument by our caller. */
@ -57,6 +58,7 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
gdb_assert (status.kind == TARGET_WAITKIND_FORKED);
pid = ptid_get_pid (ptid);
last_tp = find_thread_pid (ptid);
}
if (ptrace (PT_GET_PROCESS_STATE, pid,
@ -68,14 +70,39 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
if (follow_child)
{
inferior_ptid = pid_to_ptid (fpid);
detach_breakpoints (pid);
/* Copy user stepping state to the new inferior thread. */
struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
CORE_ADDR step_range_start = last_tp->step_range_start;
CORE_ADDR step_range_end = last_tp->step_range_end;
struct frame_id step_frame_id = last_tp->step_frame_id;
/* Reset breakpoints in the child as appropriate. */
follow_inferior_reset_breakpoints ();
struct thread_info *tp;
/* Otherwise, deleting the parent would get rid of this
breakpoint. */
last_tp->step_resume_breakpoint = NULL;
/* Before detaching from the parent, remove all breakpoints from
it. */
detach_breakpoints (pid);
if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
perror_with_name (("ptrace"));
/* Delete the parent. */
delete_thread_silent (last_tp->ptid);
/* Add the child. */
inferior_ptid = pid_to_ptid (fpid);
tp = add_thread_silent (inferior_ptid);
tp->step_resume_breakpoint = step_resume_breakpoint;
tp->step_range_start = step_range_start;
tp->step_range_end = step_range_end;
tp->step_frame_id = step_frame_id;
/* Reset breakpoints in the child as appropriate. */
follow_inferior_reset_breakpoints ();
}
else
{

View file

@ -412,6 +412,7 @@ inf_ttrace_follow_fork (struct target_ops *ops, int follow_child)
pid_t pid, fpid;
lwpid_t lwpid, flwpid;
ttstate_t tts;
struct thread_info *last_tp = NULL;
/* FIXME: kettenis/20050720: This stuff should really be passed as
an argument by our caller. */
@ -425,6 +426,7 @@ inf_ttrace_follow_fork (struct target_ops *ops, int follow_child)
pid = ptid_get_pid (ptid);
lwpid = ptid_get_lwp (ptid);
last_tp = find_thread_pid (ptid);
}
/* Get all important details that core GDB doesn't (and shouldn't)
@ -452,6 +454,18 @@ inf_ttrace_follow_fork (struct target_ops *ops, int follow_child)
if (follow_child)
{
/* Copy user stepping state to the new inferior thread. */
struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
CORE_ADDR step_range_start = last_tp->step_range_start;
CORE_ADDR step_range_end = last_tp->step_range_end;
struct frame_id step_frame_id = last_tp->step_frame_id;
struct thread_info *tp;
/* Otherwise, deleting the parent would get rid of this
breakpoint. */
last_tp->step_resume_breakpoint = NULL;
inferior_ptid = ptid_build (fpid, flwpid, 0);
detach_breakpoints (pid);
@ -530,6 +544,11 @@ Detaching after fork from child process %ld.\n"), (long)fpid);
memset (ti->private, 0,
sizeof (struct inf_ttrace_private_thread_info));
ti->step_resume_breakpoint = step_resume_breakpoint;
ti->step_range_start = step_range_start;
ti->step_range_end = step_range_end;
ti->step_frame_id = step_frame_id;
/* Reset breakpoints in the child as appropriate. */
follow_inferior_reset_breakpoints ();
}

View file

@ -177,19 +177,6 @@ int stop_stack_dummy;
int stopped_by_random_signal;
/* Range to single step within.
If this is nonzero, respond to a single-step signal
by continuing to step if the pc is in this range. */
CORE_ADDR step_range_start; /* Inclusive */
CORE_ADDR step_range_end; /* Exclusive */
/* Stack frame address as of when stepping command was issued.
This is how we know when we step into a subroutine call,
and how to set the frame for the breakpoint used to step out. */
struct frame_id step_frame_id;
enum step_over_calls_kind step_over_calls;
/* If stepping, nonzero means step count is > 1
@ -800,21 +787,22 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
{
for (; count > 0; count--)
{
struct thread_info *tp = inferior_thread ();
clear_proceed_status ();
frame = get_current_frame ();
if (!frame) /* Avoid coredump here. Why tho? */
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
tp->step_frame_id = get_frame_id (frame);
if (!single_inst)
{
find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
if (step_range_end == 0)
find_pc_line_pc_range (stop_pc,
&tp->step_range_start, &tp->step_range_end);
if (tp->step_range_end == 0)
{
char *name;
if (find_pc_partial_function (stop_pc, &name, &step_range_start,
&step_range_end) == 0)
if (find_pc_partial_function (stop_pc, &name,
&tp->step_range_start,
&tp->step_range_end) == 0)
error (_("Cannot find bounds of current function"));
target_terminal_ours ();
@ -826,7 +814,7 @@ which has no line number information.\n"), name);
else
{
/* Say we are stepping, but stop after one insn whatever it does. */
step_range_start = step_range_end = 1;
tp->step_range_start = tp->step_range_end = 1;
if (!skip_subroutines)
/* It is stepi.
Don't step over function calls, not even to functions lacking
@ -905,27 +893,34 @@ step_once (int skip_subroutines, int single_inst, int count, int thread)
if (count > 0)
{
/* Don't assume THREAD is a valid thread id. It is set to -1 if
the longjmp breakpoint was not required. Use the
INFERIOR_PTID thread instead, which is the same thread when
THREAD is set. */
struct thread_info *tp = inferior_thread ();
clear_proceed_status ();
frame = get_current_frame ();
if (!frame) /* Avoid coredump here. Why tho? */
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
tp->step_frame_id = get_frame_id (frame);
if (!single_inst)
{
find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
find_pc_line_pc_range (stop_pc,
&tp->step_range_start, &tp->step_range_end);
/* If we have no line info, switch to stepi mode. */
if (step_range_end == 0 && step_stop_if_no_debug)
if (tp->step_range_end == 0 && step_stop_if_no_debug)
{
step_range_start = step_range_end = 1;
tp->step_range_start = tp->step_range_end = 1;
}
else if (step_range_end == 0)
else if (tp->step_range_end == 0)
{
char *name;
if (find_pc_partial_function (stop_pc, &name, &step_range_start,
&step_range_end) == 0)
if (find_pc_partial_function (stop_pc, &name,
&tp->step_range_start,
&tp->step_range_end) == 0)
error (_("Cannot find bounds of current function"));
target_terminal_ours ();
@ -937,7 +932,7 @@ which has no line number information.\n"), name);
else
{
/* Say we are stepping, but stop after one insn whatever it does. */
step_range_start = step_range_end = 1;
tp->step_range_start = tp->step_range_end = 1;
if (!skip_subroutines)
/* It is stepi.
Don't step over function calls, not even to functions lacking
@ -1145,6 +1140,7 @@ until_next_command (int from_tty)
CORE_ADDR pc;
struct symbol *func;
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
clear_proceed_status ();
@ -1164,19 +1160,19 @@ until_next_command (int from_tty)
if (msymbol == NULL)
error (_("Execution is not within a known function."));
step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
step_range_end = pc;
tp->step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
tp->step_range_end = pc;
}
else
{
sal = find_pc_line (pc, 0);
step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
step_range_end = sal.end;
tp->step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
tp->step_range_end = sal.end;
}
step_over_calls = STEP_OVER_ALL;
step_frame_id = get_frame_id (frame);
tp->step_frame_id = get_frame_id (frame);
step_multi = 0; /* Only one call to proceed */

View file

@ -309,24 +309,6 @@ extern int stop_stack_dummy;
extern int stopped_by_random_signal;
/* Range to single step within.
If this is nonzero, respond to a single-step signal
by continuing to step if the pc is in this range.
If step_range_start and step_range_end are both 1, it means to step for
a single instruction (FIXME: it might clean up wait_for_inferior in a
minor way if this were changed to the address of the instruction and
that address plus one. But maybe not.). */
extern CORE_ADDR step_range_start; /* Inclusive */
extern CORE_ADDR step_range_end; /* Exclusive */
/* Stack frame address as of when stepping command was issued.
This is how we know when we step into a subroutine call,
and how to set the frame for the breakpoint used to step out. */
extern struct frame_id step_frame_id;
/* 1 means step over all subroutine calls.
-1 means step over calls to undebuggable functions. */

View file

@ -73,9 +73,7 @@ static int follow_fork (void);
static void set_schedlock_func (char *args, int from_tty,
struct cmd_list_element *c);
struct thread_stepping_state;
static int currently_stepping (struct thread_stepping_state *tss);
static int currently_stepping (struct thread_info *tp);
static void xdb_handle_command (char *args, int from_tty);
@ -216,31 +214,6 @@ static struct cmd_list_element *stop_command;
static struct symbol *step_start_function;
/* Nonzero if we are presently stepping over a breakpoint.
If we hit a breakpoint or watchpoint, and then continue,
we need to single step the current thread with breakpoints
disabled, to avoid hitting the same breakpoint or
watchpoint again. And we should step just a single
thread and keep other threads stopped, so that
other threads don't miss breakpoints while they are removed.
So, this variable simultaneously means that we need to single
step the current thread, keep other threads stopped, and that
breakpoints should be removed while we step.
This variable is set either:
- in proceed, when we resume inferior on user's explicit request
- in keep_going, if handle_inferior_event decides we need to
step over breakpoint.
The variable is cleared in clear_proceed_status, called every
time before we call proceed. The proceed calls wait_for_inferior,
which calls handle_inferior_event in a loop, and until
wait_for_inferior exits, this variable is changed only by keep_going. */
static int stepping_over_breakpoint;
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
static int stop_on_solib_events;
@ -280,34 +253,15 @@ struct regcache *stop_registers;
static int stop_print_frame;
/* Step-resume or longjmp-resume breakpoint. */
static struct breakpoint *step_resume_breakpoint = NULL;
/* This is a cached copy of the pid/waitstatus of the last event
returned by target_wait()/deprecated_target_wait_hook(). This
information is returned by get_last_target_status(). */
static ptid_t target_last_wait_ptid;
static struct target_waitstatus target_last_waitstatus;
/* Context-switchable data. */
struct thread_stepping_state
{
/* Should we step over breakpoint next time keep_going
is called? */
int stepping_over_breakpoint;
int current_line;
struct symtab *current_symtab;
int step_after_step_resume_breakpoint;
int stepping_through_solib_after_catch;
bpstat stepping_through_solib_catchpoints;
};
struct thread_stepping_state gtss;
struct thread_stepping_state *tss = &gtss;
static void context_switch (ptid_t ptid);
void init_thread_stepping_state (struct thread_stepping_state *tss);
void init_thread_stepping_state (struct thread_info *tss);
void init_infwait_state (void);
@ -359,6 +313,8 @@ follow_fork (void)
void
follow_inferior_reset_breakpoints (void)
{
struct thread_info *tp = inferior_thread ();
/* Was there a step_resume breakpoint? (There was if the user
did a "next" at the fork() call.) If so, explicitly reset its
thread number.
@ -370,8 +326,8 @@ follow_inferior_reset_breakpoints (void)
"threads". We must update the bp's notion of which thread
it is for, or it'll be ignored when it triggers. */
if (step_resume_breakpoint)
breakpoint_re_set_thread (step_resume_breakpoint);
if (tp->step_resume_breakpoint)
breakpoint_re_set_thread (tp->step_resume_breakpoint);
/* Reinsert all breakpoints in the child. The user may have set
breakpoints after catching the fork, in which case those
@ -389,6 +345,7 @@ follow_exec (ptid_t pid, char *execd_pathname)
{
ptid_t saved_pid = pid;
struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
@ -414,9 +371,9 @@ follow_exec (ptid_t pid, char *execd_pathname)
/* If there was one, it's gone now. We cannot truly step-to-next
statement through an exec(). */
step_resume_breakpoint = NULL;
step_range_start = 0;
step_range_end = 0;
th->step_resume_breakpoint = NULL;
th->step_range_start = 0;
th->step_range_end = 0;
/* What is this a.out's name? */
printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
@ -944,14 +901,15 @@ resume (int step, enum target_signal sig)
struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
QUIT;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: resume (step=%d, signal=%d), "
"stepping_over_breakpoint=%d\n",
step, sig, stepping_over_breakpoint);
"trap_expected=%d\n",
step, sig, tp->trap_expected);
/* Some targets (e.g. Solaris x86) have a kernel bug when stepping
over an instruction that causes a page fault without triggering
@ -988,7 +946,7 @@ a command like `return' or `jump' to continue execution."));
comments in the handle_inferior event for dealing with 'random
signals' explain what we do instead. */
if (use_displaced_stepping (gdbarch)
&& stepping_over_breakpoint
&& tp->trap_expected
&& sig == TARGET_SIGNAL_0)
{
if (!displaced_step_prepare (inferior_ptid))
@ -1072,7 +1030,7 @@ a command like `return' or `jump' to continue execution."));
}
if ((step || singlestep_breakpoints_inserted_p)
&& stepping_over_breakpoint)
&& tp->trap_expected)
{
/* We're allowing a thread to run past a breakpoint it has
hit, by single-stepping the thread with the breakpoint
@ -1112,7 +1070,7 @@ a command like `return' or `jump' to continue execution."));
if (debug_displaced
&& use_displaced_stepping (gdbarch)
&& stepping_over_breakpoint)
&& tp->trap_expected)
{
struct regcache *resume_regcache = get_thread_regcache (resume_ptid);
CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
@ -1138,10 +1096,16 @@ a command like `return' or `jump' to continue execution."));
void
clear_proceed_status (void)
{
stepping_over_breakpoint = 0;
step_range_start = 0;
step_range_end = 0;
step_frame_id = null_frame_id;
if (!ptid_equal (inferior_ptid, null_ptid))
{
struct thread_info *tp = inferior_thread ();
tp->trap_expected = 0;
tp->step_range_start = 0;
tp->step_range_end = 0;
tp->step_frame_id = null_frame_id;
}
step_over_calls = STEP_OVER_UNDEBUGGABLE;
stop_after_trap = 0;
stop_soon = NO_STOP_QUIETLY;
@ -1201,11 +1165,6 @@ prepare_to_proceed (int step)
return 0;
}
/* Record the pc of the program the last time it stopped. This is
just used internally by wait_for_inferior, but need to be preserved
over calls to it and cleared when the inferior is started. */
static CORE_ADDR prev_pc;
/* Basic routine for continuing the program in various fashions.
ADDR is the address to resume at, or -1 for resume where stopped.
@ -1223,6 +1182,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
{
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp;
CORE_ADDR pc = regcache_read_pc (regcache);
int oneproc = 0;
@ -1278,9 +1238,12 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
oneproc = 1;
}
/* prepare_to_proceed may change the current thread. */
tp = inferior_thread ();
if (oneproc)
{
stepping_over_breakpoint = 1;
tp->trap_expected = 1;
/* If displaced stepping is enabled, we can step over the
breakpoint without hitting it, so leave all breakpoints
inserted. Otherwise we need to disable all breakpoints, step
@ -1293,7 +1256,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
/* We can insert breakpoints if we're not trying to step over one,
or if we are stepping over one but we're using displaced stepping
to do so. */
if (! stepping_over_breakpoint || use_displaced_stepping (gdbarch))
if (! tp->trap_expected || use_displaced_stepping (gdbarch))
insert_breakpoints ();
if (siggnal != TARGET_SIGNAL_DEFAULT)
@ -1331,10 +1294,10 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
are not guaranteed the inferior is stopped and so the regcache_read_pc ()
call can fail. Setting the prev_pc value here ensures the value is
updated correctly when the inferior is stopped. */
prev_pc = regcache_read_pc (get_current_regcache ());
tp->prev_pc = regcache_read_pc (get_current_regcache ());
/* Fill in with reasonable starting values. */
init_thread_stepping_state (tss);
init_thread_stepping_state (tp);
/* Reset to normal state. */
init_infwait_state ();
@ -1361,7 +1324,6 @@ start_remote (int from_tty)
{
init_wait_for_inferior ();
stop_soon = STOP_QUIETLY_REMOTE;
stepping_over_breakpoint = 0;
/* Always go on waiting for the target, regardless of the mode. */
/* FIXME: cagney/1999-09-23: At present it isn't possible to
@ -1393,7 +1355,6 @@ void
init_wait_for_inferior (void)
{
/* These are meaningless until the first time through wait_for_inferior. */
prev_pc = 0;
breakpoint_init_inferior (inf_starting);
@ -1410,7 +1371,6 @@ init_wait_for_inferior (void)
target_last_wait_ptid = minus_one_ptid;
init_thread_stepping_state (tss);
previous_inferior_ptid = null_ptid;
init_infwait_state ();
@ -1455,6 +1415,10 @@ enum infwait_states infwait_state;
struct execution_control_state
{
ptid_t ptid;
/* The thread that got the event, if this was a thread event; NULL
otherwise. */
struct thread_info *event_thread;
struct target_waitstatus ws;
int random_signal;
CORE_ADDR stop_func_start;
@ -1481,6 +1445,53 @@ static void keep_going (struct execution_control_state *ecs);
static void print_stop_reason (enum inferior_stop_reason stop_reason,
int stop_info);
/* Callback for iterate_over_threads. */
static int
delete_step_resume_breakpoint_callback (struct thread_info *info, void *data)
{
if (is_exited (info->ptid))
return 0;
delete_step_resume_breakpoint (info);
return 0;
}
/* In all-stop, delete the step resume breakpoint of any thread that
had one. In non-stop, delete the step resume breakpoint of the
thread that just stopped. */
static void
delete_step_thread_step_resume_breakpoint (void)
{
if (!target_has_execution
|| ptid_equal (inferior_ptid, null_ptid))
/* If the inferior has exited, we have already deleted the step
resume breakpoints out of GDB's lists. */
return;
if (non_stop)
{
/* If in non-stop mode, only delete the step-resume or
longjmp-resume breakpoint of the thread that just stopped
stepping. */
struct thread_info *tp = inferior_thread ();
delete_step_resume_breakpoint (tp);
}
else
/* In all-stop mode, delete all step-resume and longjmp-resume
breakpoints of any thread that had them. */
iterate_over_threads (delete_step_resume_breakpoint_callback, NULL);
}
/* A cleanup wrapper. */
static void
delete_step_thread_step_resume_breakpoint_cleanup (void *arg)
{
delete_step_thread_step_resume_breakpoint ();
}
/* Wait for control to return from inferior to debugger.
If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
@ -1505,8 +1516,8 @@ wait_for_inferior (int treat_exec_as_sigtrap)
(gdb_stdlog, "infrun: wait_for_inferior (treat_exec_as_sigtrap=%d)\n",
treat_exec_as_sigtrap);
old_cleanups = make_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint);
old_cleanups =
make_cleanup (delete_step_thread_step_resume_breakpoint_cleanup, NULL);
ecs = &ecss;
memset (ecs, 0, sizeof (*ecs));
@ -1531,6 +1542,8 @@ wait_for_inferior (int treat_exec_as_sigtrap)
else
ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
ecs->event_thread = find_thread_pid (ecs->ptid);
if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
{
xfree (ecs->ws.value.execd_pathname);
@ -1544,6 +1557,7 @@ wait_for_inferior (int treat_exec_as_sigtrap)
if (!ecs->wait_some_more)
break;
}
do_cleanups (old_cleanups);
}
@ -1605,12 +1619,14 @@ fetch_inferior_event (void *client_data)
thread. */
context_switch (ecs->ptid);
ecs->event_thread = find_thread_pid (ecs->ptid);
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
if (!ecs->wait_some_more)
{
delete_step_resume_breakpoint (&step_resume_breakpoint);
delete_step_thread_step_resume_breakpoint ();
if (stop_soon == NO_STOP_QUIETLY)
normal_stop ();
@ -1642,7 +1658,7 @@ init_execution_control_state (struct execution_control_state *ecs)
/* Clear context switchable stepping state. */
void
init_thread_stepping_state (struct thread_stepping_state *tss)
init_thread_stepping_state (struct thread_info *tss)
{
struct symtab_and_line sal;
@ -1651,7 +1667,7 @@ init_thread_stepping_state (struct thread_stepping_state *tss)
tss->stepping_through_solib_after_catch = 0;
tss->stepping_through_solib_catchpoints = NULL;
sal = find_pc_line (prev_pc, 0);
sal = find_pc_line (tss->prev_pc, 0);
tss->current_line = sal.line;
tss->current_symtab = sal.symtab;
}
@ -1696,14 +1712,7 @@ context_switch (ptid_t ptid)
if (in_thread_list (inferior_ptid) && in_thread_list (ptid))
{ /* Perform infrun state context switch: */
/* Save infrun state for the old thread. */
save_infrun_state (inferior_ptid, prev_pc,
stepping_over_breakpoint, step_resume_breakpoint,
step_range_start,
step_range_end, &step_frame_id,
tss->stepping_over_breakpoint,
tss->stepping_through_solib_after_catch,
tss->stepping_through_solib_catchpoints,
tss->current_line, tss->current_symtab,
save_infrun_state (inferior_ptid,
cmd_continuation, intermediate_continuation,
proceed_to_finish,
step_over_calls,
@ -1713,14 +1722,7 @@ context_switch (ptid_t ptid)
stop_bpstat);
/* Load infrun state for the new thread. */
load_infrun_state (ptid, &prev_pc,
&stepping_over_breakpoint, &step_resume_breakpoint,
&step_range_start,
&step_range_end, &step_frame_id,
&tss->stepping_over_breakpoint,
&tss->stepping_through_solib_after_catch,
&tss->stepping_through_solib_catchpoints,
&tss->current_line, &tss->current_symtab,
load_infrun_state (ptid,
&cmd_continuation, &intermediate_continuation,
&proceed_to_finish,
&step_over_calls,
@ -1817,8 +1819,8 @@ adjust_pc_after_break (struct execution_control_state *ecs)
if (singlestep_breakpoints_inserted_p
|| !ptid_equal (ecs->ptid, inferior_ptid)
|| !currently_stepping (tss)
|| prev_pc == breakpoint_pc)
|| !currently_stepping (ecs->event_thread)
|| ecs->event_thread->prev_pc == breakpoint_pc)
regcache_write_pc (regcache, breakpoint_pc);
}
}
@ -2254,6 +2256,8 @@ targets should add new threads to the thread list themselves in non-stop mode.")
the fact that we were supposed to switch back. */
if (stop_signal == TARGET_SIGNAL_TRAP)
{
struct thread_info *tp;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: handling deferred step\n");
@ -2347,6 +2351,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
the context we want to use. Just fudge our
state and continue. */
ecs->ptid = singlestep_ptid;
ecs->event_thread = find_thread_pid (ecs->ptid);
stop_pc = new_singlestep_pc;
}
else
@ -2406,7 +2411,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
infwait_state = infwait_thread_hop_state;
}
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
registers_changed ();
return;
@ -2495,7 +2500,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
&ecs->stop_func_start, &ecs->stop_func_end);
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (current_gdbarch);
tss->stepping_over_breakpoint = 0;
ecs->event_thread->stepping_over_breakpoint = 0;
bpstat_clear (&stop_bpstat);
stop_step = 0;
stop_print_frame = 1;
@ -2503,9 +2508,9 @@ targets should add new threads to the thread list themselves in non-stop mode.")
stopped_by_random_signal = 0;
if (stop_signal == TARGET_SIGNAL_TRAP
&& stepping_over_breakpoint
&& ecs->event_thread->trap_expected
&& gdbarch_single_step_through_delay_p (current_gdbarch)
&& currently_stepping (tss))
&& currently_stepping (ecs->event_thread))
{
/* We're trying to step off a breakpoint. Turns out that we're
also on an instruction that needs to be stepped multiple
@ -2517,11 +2522,11 @@ targets should add new threads to the thread list themselves in non-stop mode.")
get_current_frame ());
if (debug_infrun && step_through_delay)
fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n");
if (step_range_end == 0 && step_through_delay)
if (ecs->event_thread->step_range_end == 0 && step_through_delay)
{
/* The user issued a continue when stopped at a breakpoint.
Set up for another trap and get out of here. */
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
return;
}
@ -2533,7 +2538,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
case, don't decide that here, just set
ecs->stepping_over_breakpoint, making sure we
single-step again before breakpoints are re-inserted. */
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
}
}
@ -2541,7 +2546,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
The alternatives are:
1) stop_stepping and return; to really stop and return to the debugger,
2) keep_going and return to start up again
(set tss->stepping_over_breakpoint to 1 to single step once)
(set ecs->event_thread->stepping_over_breakpoint to 1 to single step once)
3) set ecs->random_signal to 1, and the decision between 1 and 2
will be made according to the signal handling tables. */
@ -2560,7 +2565,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
breakpoint is always inserted at the original instruction;
non-standard signals can't be explained by the breakpoint. */
if (stop_signal == TARGET_SIGNAL_TRAP
|| (! stepping_over_breakpoint
|| (! ecs->event_thread->trap_expected
&& breakpoint_inserted_here_p (stop_pc)
&& (stop_signal == TARGET_SIGNAL_ILL
|| stop_signal == TARGET_SIGNAL_SEGV
@ -2638,8 +2643,9 @@ targets should add new threads to the thread list themselves in non-stop mode.")
if (stop_signal == TARGET_SIGNAL_TRAP)
ecs->random_signal
= !(bpstat_explains_signal (stop_bpstat)
|| stepping_over_breakpoint
|| (step_range_end && step_resume_breakpoint == NULL));
|| ecs->event_thread->trap_expected
|| (ecs->event_thread->step_range_end
&& ecs->event_thread->step_resume_breakpoint == NULL));
else
{
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
@ -2689,9 +2695,9 @@ process_event_stop_test:
if (signal_program[stop_signal] == 0)
stop_signal = TARGET_SIGNAL_0;
if (prev_pc == read_pc ()
&& stepping_over_breakpoint
&& step_resume_breakpoint == NULL)
if (ecs->event_thread->prev_pc == read_pc ()
&& ecs->event_thread->trap_expected
&& ecs->event_thread->step_resume_breakpoint == NULL)
{
/* We were just starting a new sequence, attempting to
single-step off of a breakpoint and expecting a SIGTRAP.
@ -2709,17 +2715,18 @@ process_event_stop_test:
"breakpoint\n");
insert_step_resume_breakpoint_at_frame (get_current_frame ());
tss->step_after_step_resume_breakpoint = 1;
ecs->event_thread->step_after_step_resume_breakpoint = 1;
keep_going (ecs);
return;
}
if (step_range_end != 0
if (ecs->event_thread->step_range_end != 0
&& stop_signal != TARGET_SIGNAL_0
&& stop_pc >= step_range_start && stop_pc < step_range_end
&& (ecs->event_thread->step_range_start <= stop_pc
&& stop_pc < ecs->event_thread->step_range_end)
&& frame_id_eq (get_frame_id (get_current_frame ()),
step_frame_id)
&& step_resume_breakpoint == NULL)
ecs->event_thread->step_frame_id)
&& ecs->event_thread->step_resume_breakpoint == NULL)
{
/* The inferior is about to take a signal that will take it
out of the single step range. Set a breakpoint at the
@ -2773,7 +2780,7 @@ process_event_stop_test:
fprintf_unfiltered (gdb_stdlog,
"infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
if (!gdbarch_get_longjmp_target_p (current_gdbarch)
|| !gdbarch_get_longjmp_target (current_gdbarch,
@ -2788,8 +2795,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* We're going to replace the current step-resume breakpoint
with a longjmp-resume breakpoint. */
if (step_resume_breakpoint != NULL)
delete_step_resume_breakpoint (&step_resume_breakpoint);
delete_step_resume_breakpoint (ecs->event_thread);
/* Insert a breakpoint at resume address. */
insert_longjmp_resume_breakpoint (jmp_buf_pc);
@ -2802,8 +2808,8 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
fprintf_unfiltered (gdb_stdlog,
"infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
gdb_assert (step_resume_breakpoint != NULL);
delete_step_resume_breakpoint (&step_resume_breakpoint);
gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL);
delete_step_resume_breakpoint (ecs->event_thread);
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
@ -2813,7 +2819,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
case BPSTAT_WHAT_SINGLE:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SINGLE\n");
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
/* Still need to check other stuff, at least the case
where we are stepping and step out of the right range. */
break;
@ -2841,39 +2847,17 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
return;
case BPSTAT_WHAT_STEP_RESUME:
/* This proably demands a more elegant solution, but, yeah
right...
This function's use of the simple variable
step_resume_breakpoint doesn't seem to accomodate
simultaneously active step-resume bp's, although the
breakpoint list certainly can.
If we reach here and step_resume_breakpoint is already
NULL, then apparently we have multiple active
step-resume bp's. We'll just delete the breakpoint we
stopped at, and carry on.
Correction: what the code currently does is delete a
step-resume bp, but it makes no effort to ensure that
the one deleted is the one currently stopped at. MVS */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
if (step_resume_breakpoint == NULL)
{
step_resume_breakpoint =
bpstat_find_step_resume_breakpoint (stop_bpstat);
}
delete_step_resume_breakpoint (&step_resume_breakpoint);
if (tss->step_after_step_resume_breakpoint)
delete_step_resume_breakpoint (ecs->event_thread);
if (ecs->event_thread->step_after_step_resume_breakpoint)
{
/* Back when the step-resume breakpoint was inserted, we
were trying to single-step off a breakpoint. Go back
to doing that. */
tss->step_after_step_resume_breakpoint = 0;
tss->stepping_over_breakpoint = 1;
ecs->event_thread->step_after_step_resume_breakpoint = 0;
ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
return;
}
@ -2948,19 +2932,20 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
friends) until we reach non-dld code. At that point,
we can stop stepping. */
bpstat_get_triggered_catchpoints (stop_bpstat,
&tss->
&ecs->
event_thread->
stepping_through_solib_catchpoints);
tss->stepping_through_solib_after_catch = 1;
ecs->event_thread->stepping_through_solib_after_catch = 1;
/* Be sure to lift all breakpoints, so the inferior does
actually step past this point... */
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
break;
}
else
{
/* We want to step over this breakpoint, then keep going. */
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
break;
}
}
@ -2983,7 +2968,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* Are we stepping to get the inferior out of the dynamic linker's
hook (and possibly the dld itself) after catching a shlib
event? */
if (tss->stepping_through_solib_after_catch)
if (ecs->event_thread->stepping_through_solib_after_catch)
{
#if defined(SOLIB_ADD)
/* Have we reached our destination? If not, keep going. */
@ -2991,7 +2976,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepping in dynamic linker\n");
tss->stepping_over_breakpoint = 1;
ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
return;
}
@ -3000,16 +2985,16 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
fprintf_unfiltered (gdb_stdlog, "infrun: step past dynamic linker\n");
/* Else, stop and report the catchpoint(s) whose triggering
caused us to begin stepping. */
tss->stepping_through_solib_after_catch = 0;
ecs->event_thread->stepping_through_solib_after_catch = 0;
bpstat_clear (&stop_bpstat);
stop_bpstat = bpstat_copy (tss->stepping_through_solib_catchpoints);
bpstat_clear (&tss->stepping_through_solib_catchpoints);
stop_bpstat = bpstat_copy (ecs->event_thread->stepping_through_solib_catchpoints);
bpstat_clear (&ecs->event_thread->stepping_through_solib_catchpoints);
stop_print_frame = 1;
stop_stepping (ecs);
return;
}
if (step_resume_breakpoint)
if (ecs->event_thread->step_resume_breakpoint)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
@ -3022,7 +3007,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
return;
}
if (step_range_end == 0)
if (ecs->event_thread->step_range_end == 0)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: no stepping, continue\n");
@ -3036,12 +3021,13 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
Note that step_range_end is the address of the first instruction
beyond the step range, and NOT the address of the last instruction
within it! */
if (stop_pc >= step_range_start && stop_pc < step_range_end)
if (stop_pc >= ecs->event_thread->step_range_start
&& stop_pc < ecs->event_thread->step_range_end)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n",
paddr_nz (step_range_start),
paddr_nz (step_range_end));
paddr_nz (ecs->event_thread->step_range_start),
paddr_nz (ecs->event_thread->step_range_end));
keep_going (ecs);
return;
}
@ -3076,7 +3062,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
return;
}
if (step_range_end != 1
if (ecs->event_thread->step_range_end != 1
&& (step_over_calls == STEP_OVER_UNDEBUGGABLE
|| step_over_calls == STEP_OVER_ALL)
&& get_frame_type (get_current_frame ()) == SIGTRAMP_FRAME)
@ -3100,8 +3086,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
NOTE: frame_id_eq will never report two invalid frame IDs as
being equal, so to get into this block, both the current and
previous frame must have valid frame IDs. */
if (!frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id)
&& frame_id_eq (frame_unwind_id (get_current_frame ()), step_frame_id))
if (!frame_id_eq (get_frame_id (get_current_frame ()),
ecs->event_thread->step_frame_id)
&& frame_id_eq (frame_unwind_id (get_current_frame ()),
ecs->event_thread->step_frame_id))
{
CORE_ADDR real_stop_pc;
@ -3109,8 +3097,9 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
fprintf_unfiltered (gdb_stdlog, "infrun: stepped into subroutine\n");
if ((step_over_calls == STEP_OVER_NONE)
|| ((step_range_end == 1)
&& in_prologue (prev_pc, ecs->stop_func_start)))
|| ((ecs->event_thread->step_range_end == 1)
&& in_prologue (ecs->event_thread->prev_pc,
ecs->stop_func_start)))
{
/* I presume that step_over_calls is only 0 when we're
supposed to be stepping at the assembly language level
@ -3268,7 +3257,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
}
}
if (step_range_end == 1)
if (ecs->event_thread->step_range_end == 1)
{
/* It is stepi or nexti. We always want to stop stepping after
one instruction. */
@ -3295,8 +3284,8 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
}
if ((stop_pc == stop_pc_sal.pc)
&& (tss->current_line != stop_pc_sal.line
|| tss->current_symtab != stop_pc_sal.symtab))
&& (ecs->event_thread->current_line != stop_pc_sal.line
|| ecs->event_thread->current_symtab != stop_pc_sal.symtab))
{
/* We are at the start of a different line. So stop. Note that
we don't stop if we step into the middle of a different line.
@ -3317,11 +3306,11 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
new line in mid-statement, we continue stepping. This makes
things like for(;;) statements work better.) */
step_range_start = stop_pc_sal.pc;
step_range_end = stop_pc_sal.end;
step_frame_id = get_frame_id (get_current_frame ());
tss->current_line = stop_pc_sal.line;
tss->current_symtab = stop_pc_sal.symtab;
ecs->event_thread->step_range_start = stop_pc_sal.pc;
ecs->event_thread->step_range_end = stop_pc_sal.end;
ecs->event_thread->step_frame_id = get_frame_id (get_current_frame ());
ecs->event_thread->current_line = stop_pc_sal.line;
ecs->event_thread->current_symtab = stop_pc_sal.symtab;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
@ -3331,11 +3320,11 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* Are we in the middle of stepping? */
static int
currently_stepping (struct thread_stepping_state *tss)
currently_stepping (struct thread_info *tp)
{
return (((step_range_end && step_resume_breakpoint == NULL)
|| stepping_over_breakpoint)
|| tss->stepping_through_solib_after_catch
return (((tp->step_range_end && tp->step_resume_breakpoint == NULL)
|| tp->trap_expected)
|| tp->stepping_through_solib_after_catch
|| bpstat_should_step ());
}
@ -3409,7 +3398,7 @@ step_into_function (struct execution_control_state *ecs)
insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
/* And make sure stepping stops right away then. */
step_range_end = step_range_start;
ecs->event_thread->step_range_end = ecs->event_thread->step_range_start;
}
keep_going (ecs);
}
@ -3424,15 +3413,15 @@ insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal,
/* There should never be more than one step-resume or longjmp-resume
breakpoint per thread, so we should never be setting a new
step_resume_breakpoint when one is already active. */
gdb_assert (step_resume_breakpoint == NULL);
gdb_assert (inferior_thread ()->step_resume_breakpoint == NULL);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: inserting step-resume breakpoint at 0x%s\n",
paddr_nz (sr_sal.pc));
step_resume_breakpoint = set_momentary_breakpoint (sr_sal, sr_id,
bp_step_resume);
inferior_thread ()->step_resume_breakpoint
= set_momentary_breakpoint (sr_sal, sr_id, bp_step_resume);
}
/* Insert a "step-resume breakpoint" at RETURN_FRAME.pc. This is used
@ -3501,14 +3490,14 @@ insert_longjmp_resume_breakpoint (CORE_ADDR pc)
/* There should never be more than one step-resume or longjmp-resume
breakpoint per thread, so we should never be setting a new
longjmp_resume_breakpoint when one is already active. */
gdb_assert (step_resume_breakpoint == NULL);
gdb_assert (inferior_thread ()->step_resume_breakpoint == NULL);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: inserting longjmp-resume breakpoint at 0x%s\n",
paddr_nz (pc));
step_resume_breakpoint =
inferior_thread ()->step_resume_breakpoint =
set_momentary_breakpoint_at_pc (pc, bp_longjmp_resume);
}
@ -3530,17 +3519,17 @@ static void
keep_going (struct execution_control_state *ecs)
{
/* Save the pc before execution, to compare with pc after stop. */
prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
ecs->event_thread->prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
/* If we did not do break;, it means we should keep running the
inferior and not return to debugger. */
if (stepping_over_breakpoint && stop_signal != TARGET_SIGNAL_TRAP)
if (ecs->event_thread->trap_expected && stop_signal != TARGET_SIGNAL_TRAP)
{
/* We took a signal (which we are supposed to pass through to
the inferior, else we'd have done a break above) and we
haven't yet gotten our trap. Simply continue. */
resume (currently_stepping (tss), stop_signal);
the inferior, else we'd not get here) and we haven't yet
gotten our trap. Simply continue. */
resume (currently_stepping (ecs->event_thread), stop_signal);
}
else
{
@ -3557,7 +3546,7 @@ keep_going (struct execution_control_state *ecs)
already inserted breakpoints. Therefore, we don't
care if breakpoints were already inserted, or not. */
if (tss->stepping_over_breakpoint)
if (ecs->event_thread->stepping_over_breakpoint)
{
if (! use_displaced_stepping (current_gdbarch))
/* Since we can't do a displaced step, we have to remove
@ -3581,7 +3570,7 @@ keep_going (struct execution_control_state *ecs)
}
}
stepping_over_breakpoint = tss->stepping_over_breakpoint;
ecs->event_thread->trap_expected = ecs->event_thread->stepping_over_breakpoint;
/* Do not deliver SIGNAL_TRAP (except when the user explicitly
specifies that such a signal should be delivered to the
@ -3599,7 +3588,7 @@ keep_going (struct execution_control_state *ecs)
stop_signal = TARGET_SIGNAL_0;
resume (currently_stepping (tss), stop_signal);
resume (currently_stepping (ecs->event_thread), stop_signal);
}
prepare_to_wait (ecs);
@ -3864,7 +3853,7 @@ Further execution is probably impossible.\n"));
(or should) carry around the function and does (or
should) use that when doing a frame comparison. */
if (stop_step
&& frame_id_eq (step_frame_id,
&& frame_id_eq (inferior_thread ()->step_frame_id,
get_frame_id (get_current_frame ()))
&& step_start_function == find_pc_function (stop_pc))
source_flag = SRC_LINE; /* finished step, just print source line */
@ -4372,16 +4361,17 @@ struct inferior_status *
save_inferior_status (int restore_stack_info)
{
struct inferior_status *inf_status = XMALLOC (struct inferior_status);
struct thread_info *tp = inferior_thread ();
inf_status->stop_signal = stop_signal;
inf_status->stop_pc = stop_pc;
inf_status->stop_step = stop_step;
inf_status->stop_stack_dummy = stop_stack_dummy;
inf_status->stopped_by_random_signal = stopped_by_random_signal;
inf_status->stepping_over_breakpoint = stepping_over_breakpoint;
inf_status->step_range_start = step_range_start;
inf_status->step_range_end = step_range_end;
inf_status->step_frame_id = step_frame_id;
inf_status->stepping_over_breakpoint = tp->trap_expected;
inf_status->step_range_start = tp->step_range_start;
inf_status->step_range_end = tp->step_range_end;
inf_status->step_frame_id = tp->step_frame_id;
inf_status->step_over_calls = step_over_calls;
inf_status->stop_after_trap = stop_after_trap;
inf_status->stop_soon = stop_soon;
@ -4425,15 +4415,17 @@ restore_selected_frame (void *args)
void
restore_inferior_status (struct inferior_status *inf_status)
{
struct thread_info *tp = inferior_thread ();
stop_signal = inf_status->stop_signal;
stop_pc = inf_status->stop_pc;
stop_step = inf_status->stop_step;
stop_stack_dummy = inf_status->stop_stack_dummy;
stopped_by_random_signal = inf_status->stopped_by_random_signal;
stepping_over_breakpoint = inf_status->stepping_over_breakpoint;
step_range_start = inf_status->step_range_start;
step_range_end = inf_status->step_range_end;
step_frame_id = inf_status->step_frame_id;
tp->trap_expected = inf_status->stepping_over_breakpoint;
tp->step_range_start = inf_status->step_range_start;
tp->step_range_end = inf_status->step_range_end;
tp->step_frame_id = inf_status->step_frame_id;
step_over_calls = inf_status->step_over_calls;
stop_after_trap = inf_status->stop_after_trap;
stop_soon = inf_status->stop_soon;

View file

@ -774,8 +774,20 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
}
else
{
struct thread_info *last_tp = find_thread_pid (last_ptid);
struct thread_info *tp;
char child_pid_spelling[40];
/* Copy user stepping state to the new inferior thread. */
struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
CORE_ADDR step_range_start = last_tp->step_range_start;
CORE_ADDR step_range_end = last_tp->step_range_end;
struct frame_id step_frame_id = last_tp->step_frame_id;
/* Otherwise, deleting the parent would get rid of this
breakpoint. */
last_tp->step_resume_breakpoint = NULL;
/* Needed to keep the breakpoint lists in sync. */
if (! has_vforked)
detach_breakpoints (child_pid);
@ -832,6 +844,12 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
linux_nat_switch_fork (inferior_ptid);
check_for_thread_db ();
tp = inferior_thread ();
tp->step_resume_breakpoint = step_resume_breakpoint;
tp->step_range_start = step_range_start;
tp->step_range_end = step_range_end;
tp->step_frame_id = step_frame_id;
/* Reset breakpoints in the child as appropriate. */
follow_inferior_reset_breakpoints ();
}

View file

@ -74,20 +74,21 @@ enum thread_state
static enum thread_state main_thread_state = THREAD_STOPPED;
static int main_thread_executing = 0;
extern struct thread_info*
inferior_thread (void)
{
struct thread_info *tp = find_thread_pid (inferior_ptid);
gdb_assert (tp);
return tp;
}
void
delete_step_resume_breakpoint (void *arg)
delete_step_resume_breakpoint (struct thread_info *tp)
{
struct breakpoint **breakpointp = (struct breakpoint **) arg;
struct thread_info *tp;
if (*breakpointp != NULL)
if (tp && tp->step_resume_breakpoint)
{
delete_breakpoint (*breakpointp);
for (tp = thread_list; tp; tp = tp->next)
if (tp->step_resume_breakpoint == *breakpointp)
delete_breakpoint (tp->step_resume_breakpoint);
tp->step_resume_breakpoint = NULL;
*breakpointp = NULL;
}
}
@ -442,17 +443,6 @@ gdb_list_thread_ids (struct ui_out *uiout, char **error_message)
void
load_infrun_state (ptid_t ptid,
CORE_ADDR *prev_pc,
int *trap_expected,
struct breakpoint **step_resume_breakpoint,
CORE_ADDR *step_range_start,
CORE_ADDR *step_range_end,
struct frame_id *step_frame_id,
int *stepping_over_breakpoint,
int *stepping_through_solib_after_catch,
bpstat *stepping_through_solib_catchpoints,
int *current_line,
struct symtab **current_symtab,
struct continuation **continuations,
struct continuation **intermediate_continuations,
int *proceed_to_finish,
@ -470,20 +460,6 @@ load_infrun_state (ptid_t ptid,
if (tp == NULL)
return;
*prev_pc = tp->prev_pc;
*trap_expected = tp->trap_expected;
*step_resume_breakpoint = tp->step_resume_breakpoint;
*step_range_start = tp->step_range_start;
*step_range_end = tp->step_range_end;
*step_frame_id = tp->step_frame_id;
*stepping_over_breakpoint = tp->stepping_over_breakpoint;
*stepping_through_solib_after_catch =
tp->stepping_through_solib_after_catch;
*stepping_through_solib_catchpoints =
tp->stepping_through_solib_catchpoints;
*current_line = tp->current_line;
*current_symtab = tp->current_symtab;
/* In all-stop mode, these are global state, while in non-stop mode,
they are per thread. */
if (non_stop)
@ -509,17 +485,6 @@ load_infrun_state (ptid_t ptid,
void
save_infrun_state (ptid_t ptid,
CORE_ADDR prev_pc,
int trap_expected,
struct breakpoint *step_resume_breakpoint,
CORE_ADDR step_range_start,
CORE_ADDR step_range_end,
const struct frame_id *step_frame_id,
int stepping_over_breakpoint,
int stepping_through_solib_after_catch,
bpstat stepping_through_solib_catchpoints,
int current_line,
struct symtab *current_symtab,
struct continuation *continuations,
struct continuation *intermediate_continuations,
int proceed_to_finish,
@ -537,18 +502,6 @@ save_infrun_state (ptid_t ptid,
if (tp == NULL)
return;
tp->prev_pc = prev_pc;
tp->trap_expected = trap_expected;
tp->step_resume_breakpoint = step_resume_breakpoint;
tp->step_range_start = step_range_start;
tp->step_range_end = step_range_end;
tp->step_frame_id = (*step_frame_id);
tp->stepping_over_breakpoint = stepping_over_breakpoint;
tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch;
tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
tp->current_line = current_line;
tp->current_symtab = current_symtab;
/* In all-stop mode, these are global state, while in non-stop mode,
they are per thread. */
if (non_stop)