This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/7] range stepping: gdbserver on x86/linux


This patch adds the support of range stepping in GDBserver for
x86/linux.

gdb/gdbserver:

2013-03-11  Yao Qi  <yao@codesourcery.com>

	* gdbthread.h (struct thread_info) <start, end>: New fields.
	(thread_in_range_stepping_p): Declare.
	(thread_clear_range_stepping): Declare.
	* inferiors.c (thread_clear_range_stepping): New.
	(add_thread): Call thread_clear_range_stepping.
	(thread_in_range_stepping_p): New.
	* linux-low.c (linux_wait_1): Call thread_in_range_stepping_p
	to check if report stop to GDB.
	Call thread_clear_range_stepping.
	(linux_supports_range_stepping): New.
	(linux_target_ops): Initialize 'supports_range_stepping' to
	linux_supports_range_stepping.
	* linux-low.h (struct linux_target_ops)
	<supports_range_stepping>: New field.
	* linux-x86-low.c (x86_supports_range_stepping): New.
	(the_low_target): Initialize 'supports_range_stepping' to
	* server.c (handle_v_cont): Handle action 'r'.
	(handle_v_requests): Append ";r" if target supports range
	stepping.
	* target.h (struct target_ops) <supports_range_stepping>>:
	New field.
	(target_supports_range_stepping): New macro.
---
 gdb/gdbserver/gdbthread.h     |    6 ++++++
 gdb/gdbserver/inferiors.c     |   19 +++++++++++++++++++
 gdb/gdbserver/linux-low.c     |   38 +++++++++++++++++++++++++++++++++++---
 gdb/gdbserver/linux-low.h     |    2 ++
 gdb/gdbserver/linux-x86-low.c |    7 +++++++
 gdb/gdbserver/server.c        |   40 ++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/target.h        |    6 ++++++
 7 files changed, 115 insertions(+), 3 deletions(-)

diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index 5d4955b..fbd768b 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -62,12 +62,18 @@ struct thread_info
 
   /* Branch trace target information for this thread.  */
   struct btrace_target_info *btrace;
+
+  /* The start and end address of range stepping.  */
+  CORE_ADDR start, end;
 };
 
 extern struct inferior_list all_threads;
 
 void remove_thread (struct thread_info *thread);
 void add_thread (ptid_t ptid, void *target_data);
+int thread_in_range_stepping_p (struct thread_info *thread,
+				CORE_ADDR pc);
+void thread_clear_range_stepping (struct thread_info *thread);
 
 struct thread_info *find_thread_ptid (ptid_t ptid);
 struct thread_info *gdb_id_to_thread (unsigned int);
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 6953d0e..2184a7b 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -85,6 +85,15 @@ remove_inferior (struct inferior_list *list,
     list->tail = *cur;
 }
 
+/* Clear the state of range stepping of THREAD.  */
+
+void
+thread_clear_range_stepping (struct thread_info *thread)
+{
+  thread->start = 0;
+  thread->end = 0;
+}
+
 void
 add_thread (ptid_t thread_id, void *target_data)
 {
@@ -103,6 +112,16 @@ add_thread (ptid_t thread_id, void *target_data)
 
   new_thread->target_data = target_data;
   set_inferior_regcache_data (new_thread, new_register_cache ());
+  thread_clear_range_stepping (new_thread);
+}
+
+/* Return true if THREAD is in range stepping.  PC is the value of pc
+   of THREAD.  */
+
+int
+thread_in_range_stepping_p (struct thread_info *thread, CORE_ADDR pc)
+{
+  return (pc >= thread->start && pc < thread->end);
 }
 
 ptid_t
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..e9879cc 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -2313,6 +2313,7 @@ linux_wait_1 (ptid_t ptid,
   int maybe_internal_trap;
   int report_to_gdb;
   int trace_event;
+  int in_range_stepping;
 
   /* Translate generic target options into linux options.  */
   options = __WALL;
@@ -2322,6 +2323,7 @@ linux_wait_1 (ptid_t ptid,
 retry:
   bp_explains_trap = 0;
   trace_event = 0;
+  in_range_stepping = 0;
   ourstatus->kind = TARGET_WAITKIND_IGNORE;
 
   /* If we were only supposed to resume one thread, only wait for
@@ -2615,6 +2617,9 @@ Check if we're already there.\n",
       goto retry;
     }
 
+  in_range_stepping
+    = thread_in_range_stepping_p (current_inferior,
+				  event_child->stop_pc);
   /* If GDB wanted this thread to single step, we always want to
      report the SIGTRAP, and let GDB handle it.  Watchpoints should
      always be reported.  So should signals we can't explain.  A
@@ -2624,9 +2629,12 @@ Check if we're already there.\n",
      internal breakpoint and still reporting the event to GDB.  If we
      don't, we're out of luck, GDB won't see the breakpoint hit.  */
   report_to_gdb = (!maybe_internal_trap
-		   || current_inferior->last_resume_kind == resume_step
+		   /* Report the event back to GDB if the inferior is
+		      stepping and not in range stepping.  */
+		   || (current_inferior->last_resume_kind == resume_step
+		       && !in_range_stepping)
 		   || event_child->stopped_by_watchpoint
-		   || (!step_over_finished
+		   || (!step_over_finished && !in_range_stepping
 		       && !bp_explains_trap && !trace_event)
 		   || (gdb_breakpoint_here (event_child->stop_pc)
 		       && gdb_condition_true_at_breakpoint (event_child->stop_pc)
@@ -2647,6 +2655,12 @@ Check if we're already there.\n",
 	    fprintf (stderr, "Step-over finished.\n");
 	  if (trace_event)
 	    fprintf (stderr, "Tracepoint event.\n");
+	  if (thread_in_range_stepping_p (current_inferior,
+					  event_child->stop_pc))
+	    fprintf (stderr, "Range stepping pc 0x%s [0x%s, 0x%s).\n",
+		     paddress (event_child->stop_pc),
+		     paddress (current_inferior->start),
+		     paddress (current_inferior->end));
 	}
 
       /* We're not reporting this breakpoint to GDB, so apply the
@@ -2678,7 +2692,13 @@ Check if we're already there.\n",
   if (debug_threads)
     {
       if (current_inferior->last_resume_kind == resume_step)
-	fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
+	{
+	  if (!thread_in_range_stepping_p (current_inferior,
+					   event_child->stop_pc))
+	    fprintf (stderr, "Range stepping is done, reporting event.\n");
+	  else
+	    fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
+	}
       if (event_child->stopped_by_watchpoint)
 	fprintf (stderr, "Stopped by watchpoint.\n");
       if (gdb_breakpoint_here (event_child->stop_pc))
@@ -2687,6 +2707,8 @@ Check if we're already there.\n",
 	fprintf (stderr, "Hit a non-gdbserver trap event.\n");
     }
 
+  thread_clear_range_stepping (current_inferior);
+
   /* Alright, we're going to report a stop.  */
 
   if (!non_stop && !stabilizing_threads)
@@ -5083,6 +5105,15 @@ linux_supports_agent (void)
   return 1;
 }
 
+static int
+linux_supports_range_stepping (void)
+{
+  if (*the_low_target.supports_range_stepping == NULL)
+    return 0;
+
+  return (*the_low_target.supports_range_stepping) ();
+}
+
 /* Enumerate spufs IDs for process PID.  */
 static int
 spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
@@ -5939,6 +5970,7 @@ static struct target_ops linux_target_ops = {
   NULL,
   NULL,
 #endif
+  linux_supports_range_stepping,
 };
 
 static void
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 27dd3b5..5d3e8cf 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -168,6 +168,8 @@ struct linux_target_ops
      for use as a fast tracepoint.  */
   int (*get_min_fast_tracepoint_insn_len) (void);
 
+  /* Returns true if the low target supports range stepping.  */
+  int (*supports_range_stepping) (void);
 };
 
 extern struct linux_target_ops the_low_target;
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 31657d3..1d1df95 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -3175,6 +3175,12 @@ x86_emit_ops (void)
     return &i386_emit_ops;
 }
 
+static int
+x86_supports_range_stepping (void)
+{
+  return 1;
+}
+
 /* This is initialized assuming an amd64 target.
    x86_arch_setup will correct it for i386 or amd64 targets.  */
 
@@ -3214,4 +3220,5 @@ struct linux_target_ops the_low_target =
   x86_install_fast_tracepoint_jump_pad,
   x86_emit_ops,
   x86_get_min_fast_tracepoint_insn_len,
+  x86_supports_range_stepping,
 };
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6bb36d8..aa4ddf6 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -2040,10 +2040,15 @@ handle_v_cont (char *own_buf)
   p = &own_buf[5];
   while (*p)
     {
+      CORE_ADDR start = 0;
+      CORE_ADDR end = 0;
+
       p++;
 
       if (p[0] == 's' || p[0] == 'S')
 	resume_info[i].kind = resume_step;
+      else if (p[0] == 'r')
+	resume_info[i].kind = resume_step;
       else if (p[0] == 'c' || p[0] == 'C')
 	resume_info[i].kind = resume_continue;
       else if (p[0] == 't')
@@ -2063,6 +2068,21 @@ handle_v_cont (char *own_buf)
 	    goto err;
 	  resume_info[i].sig = gdb_signal_to_host (sig);
 	}
+      else if (p[0] == 'r')
+	{
+	  char *p1;
+
+	  p = p + 1;
+	  p1 = strchr (p, ',');
+	  decode_address (&start, p, p1 - p);
+
+	  p = p1 + 1;
+	  p1 = strchr (p, ':');
+	  decode_address (&end, p, p1 - p);
+
+	  resume_info[i].sig = 0;
+	  p = p1;
+	}
       else
 	{
 	  resume_info[i].sig = 0;
@@ -2088,6 +2108,21 @@ handle_v_cont (char *own_buf)
 	    goto err;
 
 	  resume_info[i].thread = ptid;
+	  if (end > 0)
+	    {
+	      struct thread_info *tp = find_thread_ptid (ptid);
+
+	      /* GDB should not send range stepping for all threads of
+		 a process, like 'vCont;rSTART,END:pPID.-1', TP can't
+		 be NULL.  */
+	      gdb_assert (tp != NULL);
+
+	      tp->start = start;
+	      tp->end = end;
+
+	      start = 0;
+	      end = 0;
+	    }
 
 	  i++;
 	}
@@ -2311,6 +2346,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
       if (strncmp (own_buf, "vCont?", 6) == 0)
 	{
 	  strcpy (own_buf, "vCont;c;C;s;S;t");
+	  if (target_supports_range_stepping ())
+	    {
+	      own_buf = own_buf + strlen (own_buf);
+	      strcpy (own_buf, ";r");
+	    }
 	  return;
 	}
     }
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index f257459..8c0790e 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -414,6 +414,8 @@ struct target_ops
      to break a cyclic dependency.  */
   void (*read_btrace) (struct btrace_target_info *, struct buffer *, int type);
 
+  /* Return true if target supports range stepping.  */
+  int (*supports_range_stepping) (void);
 };
 
 extern struct target_ops *the_target;
@@ -549,6 +551,10 @@ int kill_inferior (int);
 #define target_read_btrace(tinfo, buffer, type)	\
   (*the_target->read_btrace) (tinfo, buffer, type)
 
+#define target_supports_range_stepping() \
+  (the_target->supports_range_stepping ? \
+   (*the_target->supports_range_stepping) () : 0)
+
 /* Start non-stop mode, returns 0 on success, -1 on failure.   */
 
 int start_non_stop (int nonstop);
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]