From 4e1c45eac7d0c2793eeb0675d7f7f8833aed5b60 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 8 Sep 2008 21:40:39 +0000 Subject: [PATCH] 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. --- gdb/ChangeLog | 73 +++++++++ gdb/gdbthread.h | 88 +++++++---- gdb/inf-ptrace.c | 35 ++++- gdb/inf-ttrace.c | 19 +++ gdb/infcmd.c | 64 ++++---- gdb/inferior.h | 18 --- gdb/infrun.c | 396 +++++++++++++++++++++++------------------------ gdb/linux-nat.c | 18 +++ gdb/thread.c | 71 ++------- 9 files changed, 438 insertions(+), 344 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ce292c8f5d9..e8cc0a7b84c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,76 @@ +2008-09-08 Pedro Alves + + 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 * bsd-uthread.c (bsd_uthread_find_new_threads): Claim the main diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index 6696017d0a0..ea13ba5ff48 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -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 */ diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c index 6899be0bc85..301d59d5862 100644 --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -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 { diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c index 0ad915761ab..cbc8ecb1232 100644 --- a/gdb/inf-ttrace.c +++ b/gdb/inf-ttrace.c @@ -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 (); } diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 1fc778ce2f8..160606faa74 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -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 */ diff --git a/gdb/inferior.h b/gdb/inferior.h index f53af8bb223..5555e91c721 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -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. */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 2d31219901d..b525edf64ff 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -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 = >ss; - 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; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 8ba6ea982f9..07ded105618 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -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 (); } diff --git a/gdb/thread.c b/gdb/thread.c index 15da5b6239e..3aedb45033c 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -74,20 +74,21 @@ enum thread_state static enum thread_state main_thread_state = THREAD_STOPPED; static int main_thread_executing = 0; -void -delete_step_resume_breakpoint (void *arg) +extern struct thread_info* +inferior_thread (void) { - struct breakpoint **breakpointp = (struct breakpoint **) arg; - struct thread_info *tp; + struct thread_info *tp = find_thread_pid (inferior_ptid); + gdb_assert (tp); + return tp; +} - if (*breakpointp != NULL) +void +delete_step_resume_breakpoint (struct thread_info *tp) +{ + if (tp && tp->step_resume_breakpoint) { - delete_breakpoint (*breakpointp); - for (tp = thread_list; tp; tp = tp->next) - if (tp->step_resume_breakpoint == *breakpointp) - tp->step_resume_breakpoint = NULL; - - *breakpointp = NULL; + delete_breakpoint (tp->step_resume_breakpoint); + tp->step_resume_breakpoint = 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)