Remove context switching in favour of accessing thread_info fields
authorPedro Alves <palves@redhat.com>
Mon, 8 Sep 2008 21:40:39 +0000 (21:40 +0000)
committerPedro Alves <palves@redhat.com>
Mon, 8 Sep 2008 21:40:39 +0000 (21:40 +0000)
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
gdb/gdbthread.h
gdb/inf-ptrace.c
gdb/inf-ttrace.c
gdb/infcmd.c
gdb/inferior.h
gdb/infrun.c
gdb/linux-nat.c
gdb/thread.c

index ce292c8f5d94a06bde7cbbe63055964a9116bd53..e8cc0a7b84c7050d27571f7b27e78927ea6ddfde 100644 (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
index 6696017d0a02d623594c2ec8365920bb1a641465..ea13ba5ff4888cd46e669bad8e6d971a25921091 100644 (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 */
index 6899be0bc858e089824460971958f0c3ad6a661f..301d59d58621720eb018dcf883545e8c6b4ca46e 100644 (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
     {
index 0ad915761ab1779316b609374810aa5178244c71..cbc8ecb12320378570b8aac983727978f27ec4e3 100644 (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 ();
     }
index 1fc778ce2f83f5d61b0e60cffd21829cb3cc099c..160606faa74abab8e12a335f0e775887ea41e9ac 100644 (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 */
 
index f53af8bb2232b7ee0e03f2c59088b6f82796622f..5555e91c7211747fbd755b9fea67b2f0d1afe47c 100644 (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.  */
 
index 2d31219901d2b5e468c79701f522f2146c32b209..b525edf64ffc2246c14fe766053dd39b891a93e0 100644 (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;
index 8ba6ea982f9ab0a88f66faaf9f96d8ede3313ace..07ded105618f410fcaa5bc017fd999226f41c725 100644 (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 ();
     }
index 15da5b6239e8580d2a60686d82ba17f79f65d10b..3aedb45033c07bcd4c2239dfec1c6209547475ab 100644 (file)
@@ -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)