[2/6,PR,gdb/25913] Implement nextc and stepc commands

Message ID 20200516172632.4803-3-ssbssa@yahoo.de
State New
Headers show
Series
  • Step program considering the source column information
Related show

Commit Message

Simon Marchi via Gdb-patches May 16, 2020, 5:26 p.m.
---
 gdb/gdbthread.h |  1 +
 gdb/infcmd.c    | 59 +++++++++++++++++++++++++++++++++++++++----------
 gdb/infrun.c    | 18 ++++++++++-----
 gdb/infrun.h    |  3 ++-
 4 files changed, 63 insertions(+), 18 deletions(-)

-- 
2.26.2

Patch

diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 717a2ad08c..461e221409 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -332,6 +332,7 @@  class thread_info : public refcounted_object
   thread_suspend_state suspend;
 
   int current_line = 0;
+  int current_column = 0;
   struct symtab *current_symtab = NULL;
 
   /* Internal stepping state.  */
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 8b01f45828..a2069c67fc 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -61,7 +61,7 @@ 
 
 static void until_next_command (int);
 
-static void step_1 (int, int, const char *);
+static void step_1 (int, int, int, const char *);
 
 #define ERROR_NO_INFERIOR \
    if (!target_has_execution) error (_("The program is not being run."));
@@ -917,7 +917,7 @@  continue_command (const char *args, int from_tty)
 /* Record in TP the starting point of a "step" or "next" command.  */
 
 static void
-set_step_frame (thread_info *tp)
+set_step_frame (thread_info *tp, bool step_column)
 {
   /* This can be removed once this function no longer implicitly relies on the
      inferior_ptid value.  */
@@ -926,7 +926,7 @@  set_step_frame (thread_info *tp)
   frame_info *frame = get_current_frame ();
 
   symtab_and_line sal = find_frame_sal (frame);
-  set_step_info (tp, frame, sal);
+  set_step_info (tp, frame, sal, step_column);
 
   CORE_ADDR pc = get_frame_pc (frame);
   tp->control.step_start_function = find_pc_function (pc);
@@ -937,7 +937,7 @@  set_step_frame (thread_info *tp)
 static void
 step_command (const char *count_string, int from_tty)
 {
-  step_1 (0, 0, count_string);
+  step_1 (0, 0, 0, count_string);
 }
 
 /* Likewise, but skip over subroutine calls as if single instructions.  */
@@ -945,7 +945,7 @@  step_command (const char *count_string, int from_tty)
 static void
 next_command (const char *count_string, int from_tty)
 {
-  step_1 (1, 0, count_string);
+  step_1 (1, 0, 0, count_string);
 }
 
 /* Likewise, but step only one instruction.  */
@@ -953,13 +953,27 @@  next_command (const char *count_string, int from_tty)
 static void
 stepi_command (const char *count_string, int from_tty)
 {
-  step_1 (0, 1, count_string);
+  step_1 (0, 1, 0, count_string);
 }
 
 static void
 nexti_command (const char *count_string, int from_tty)
 {
-  step_1 (1, 1, count_string);
+  step_1 (1, 1, 0, count_string);
+}
+
+/* Likewise, but step until instruction of another column is reached.  */
+
+static void
+stepc_command (const char *count_string, int from_tty)
+{
+  step_1 (0, 0, 1, count_string);
+}
+
+static void
+nextc_command (const char *count_string, int from_tty)
+{
+  step_1 (1, 0, 1, count_string);
 }
 
 /* Data for the FSM that manages the step/next/stepi/nexti
@@ -976,6 +990,9 @@  struct step_command_fsm : public thread_fsm
   /* If true, this is a stepi/nexti, otherwise a step/step.  */
   int single_inst;
 
+  /* If true, this is a stepc/nextc, otherwise a step/next.  */
+  int step_column;
+
   explicit step_command_fsm (struct interp *cmd_interp)
     : thread_fsm (cmd_interp)
   {
@@ -992,10 +1009,12 @@  struct step_command_fsm : public thread_fsm
 static void
 step_command_fsm_prepare (struct step_command_fsm *sm,
 			  int skip_subroutines, int single_inst,
+			  int step_column,
 			  int count, struct thread_info *thread)
 {
   sm->skip_subroutines = skip_subroutines;
   sm->single_inst = single_inst;
+  sm->step_column = step_column;
   sm->count = count;
 
   /* Leave the si command alone.  */
@@ -1008,7 +1027,8 @@  step_command_fsm_prepare (struct step_command_fsm *sm,
 static int prepare_one_step (thread_info *, struct step_command_fsm *sm);
 
 static void
-step_1 (int skip_subroutines, int single_inst, const char *count_string)
+step_1 (int skip_subroutines, int single_inst, int step_column,
+	const char *count_string)
 {
   int count;
   int async_exec;
@@ -1037,7 +1057,7 @@  step_1 (int skip_subroutines, int single_inst, const char *count_string)
   thr->thread_fsm = step_sm;
 
   step_command_fsm_prepare (step_sm, skip_subroutines,
-			    single_inst, count, thr);
+			    single_inst, step_column, count, thr);
 
   /* Do only one step for now, before returning control to the event
      loop.  Let the continuation figure out how many other steps we
@@ -1115,7 +1135,7 @@  prepare_one_step (thread_info *tp, struct step_command_fsm *sm)
     {
       struct frame_info *frame = get_current_frame ();
 
-      set_step_frame (tp);
+      set_step_frame (tp, sm->step_column);
 
       if (!sm->single_inst)
 	{
@@ -1489,7 +1509,7 @@  until_next_command (int from_tty)
   struct until_next_fsm *sm;
 
   clear_proceed_status (0);
-  set_step_frame (tp);
+  set_step_frame (tp, false);
 
   frame = get_current_frame ();
 
@@ -1946,7 +1966,7 @@  finish_command (const char *arg, int from_tty)
 	 called by that frame.  We don't use the magic "1" value for
 	 step_range_end, because then infrun will think this is nexti,
 	 and not step over the rest of this inlined function call.  */
-      set_step_info (tp, frame, {});
+      set_step_info (tp, frame, {}, false);
       tp->control.step_range_start = get_frame_pc (frame);
       tp->control.step_range_end = tp->control.step_range_start;
       tp->control.step_over_calls = STEP_OVER_ALL;
@@ -3348,6 +3368,21 @@  Argument N means step N times (or till program stops for another \
 reason)."));
   add_com_alias ("s", "step", class_run, 1);
 
+  add_com ("nextc", class_run, nextc_command, _("\
+Step program, proceeding through subroutine calls.\n\
+Usage: next [N]\n\
+Unlike \"stepc\", if the current source line and column calls\n\
+a subroutine, this command does not enter the subroutine, but\n\
+instead steps over the call."));
+  add_com_alias ("nc", "nextc", class_run, 0);
+
+  add_com ("stepc", class_run, stepc_command, _("\
+Step program until it reaches a different source line or column.\n\
+Usage: stepc [N]\n\
+Argument N means step N times (or till program stops for another \
+reason)."));
+  add_com_alias ("sc", "stepc", class_run, 0);
+
   c = add_com ("until", class_run, until_command, _("\
 Execute until past the current line or past a LOCATION.\n\
 Execute until the program reaches a source line greater than the current\n\
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 601a2acca4..6bc4392de6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4112,7 +4112,7 @@  fetch_inferior_event (void *client_data)
 
 void
 set_step_info (thread_info *tp, struct frame_info *frame,
-	       struct symtab_and_line sal)
+	       struct symtab_and_line sal, bool step_column)
 {
   /* This can be removed once this function no longer implicitly relies on the
      inferior_ptid value.  */
@@ -4123,6 +4123,7 @@  set_step_info (thread_info *tp, struct frame_info *frame,
 
   tp->current_symtab = sal.symtab;
   tp->current_line = sal.line;
+  tp->current_column = step_column ? sal.column : 0;
 }
 
 /* Clear context switchable stepping state.  */
@@ -7209,7 +7210,9 @@  process_event_stop_test (struct execution_control_state *ecs)
 	     first.  Otherwise stop at the call site.  */
 
 	  if (call_sal.line == ecs->event_thread->current_line
-	      && call_sal.symtab == ecs->event_thread->current_symtab)
+	      && call_sal.symtab == ecs->event_thread->current_symtab
+	      && (ecs->event_thread->current_column == 0
+		  || call_sal.column == ecs->event_thread->current_column))
 	    {
 	      step_into_inline_frame (ecs->event_thread);
 	      if (inline_frame_is_marked_for_skip (false, ecs->event_thread))
@@ -7228,7 +7231,9 @@  process_event_stop_test (struct execution_control_state *ecs)
 	     different source line.  Otherwise continue through the
 	     inlined function.  */
 	  if (call_sal.line == ecs->event_thread->current_line
-	      && call_sal.symtab == ecs->event_thread->current_symtab)
+	      && call_sal.symtab == ecs->event_thread->current_symtab
+	      && (ecs->event_thread->current_column == 0
+		  || call_sal.column == ecs->event_thread->current_column))
 	    keep_going (ecs);
 	  else
 	    end_stepping_range (ecs);
@@ -7262,7 +7267,9 @@  process_event_stop_test (struct execution_control_state *ecs)
   bool refresh_step_info = true;
   if ((ecs->event_thread->suspend.stop_pc == stop_pc_sal.pc)
       && (ecs->event_thread->current_line != stop_pc_sal.line
- 	  || ecs->event_thread->current_symtab != stop_pc_sal.symtab))
+	  || ecs->event_thread->current_symtab != stop_pc_sal.symtab
+	  || (ecs->event_thread->current_column != 0
+	      && ecs->event_thread->current_column != stop_pc_sal.column)))
     {
       if (stop_pc_sal.is_stmt)
 	{
@@ -7309,7 +7316,8 @@  process_event_stop_test (struct execution_control_state *ecs)
   ecs->event_thread->control.step_range_end = stop_pc_sal.end;
   ecs->event_thread->control.may_range_step = 1;
   if (refresh_step_info)
-    set_step_info (ecs->event_thread, frame, stop_pc_sal);
+    set_step_info (ecs->event_thread, frame, stop_pc_sal,
+		   ecs->event_thread->current_column != 0);
 
   if (debug_infrun)
      fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 9808541351..28c7582996 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -154,7 +154,8 @@  extern int stepping_past_nonsteppable_watchpoint (void);
 /* Record in TP the frame and location we're currently stepping through.  */
 extern void set_step_info (thread_info *tp,
 			   struct frame_info *frame,
-			   struct symtab_and_line sal);
+			   struct symtab_and_line sal,
+			   bool step_column);
 
 /* Several print_*_reason helper functions to print why the inferior
    has stopped to the passed in UIOUT.  */