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]

[gdbserver 1/2] x86-linux Z0 support, and support multiple breakpoints at the same address.


This patch adds support for Z0 breakpoints in x86-linux
gdbserver.

That current problem this aims at solving is, if both
gdbserver internal breakpoints and GDB breakpoints are
installed in memory as int3 traps, GDBserver presently
has no way to know that it should also report the
trap to GDB, in addition to handling the internal
breakpoint.  This hasn't been a serious problem so far,
because internal gdbserver breakpoints have only been
mainly useful for the thread event breakpoint, seldom used
nowadays, and for the reinsert breakpoint used to step
over that thread event breakpoint.  Normally, users aren't
setting breakpoints in that code themselves.  If they do,
they're breakpoint is just ignored by GDBserver, and GDB
never sees the hit.  It's a bit harder to try this out
noawadays, since on non-ancient kernels with clone events
support, GDBserver doesn't use this breakpoint at all.

With tracepoints implemented as gdbserver internal breakpoints,
this changes, and becomes a much more annoying problem.  GDB
breakpoints on top of tracepoints are much more frequent than
one would expect.  It's quite frequent to set breakpoints close
or on top of tracepoints when you're debugging what to debug,
so to speak, or when you want to debug something while the
tracing is ongoing, in non-stop mode.

This not only fixes _user_ breakpoints set on top of
tracepoints, but also fixes internal GDB breakpoints on
top of tracepoints.  When that happens, you usually find
that run control breaks.  Consider:

 function ()
 {
      foo ();  << stopped here.
      bar ();  << tracepoint here.
 }

Say you're debugging function, you have your thread
stopped at the `foo ();' line, and tracing is on.  Now, you
do a "next".  Instead of the thread stopping at the `bar ();' line,
the program just runs away!  This is because "next" installs
an internal breakpoint at the resume address of "foo" (called
a step-resume breakpoint, in GDB lingo).  Since that ends up exactly
on top of the tracepoint, and if the target has no way to know
that it should report the trap to GDB, it just collects the
tracepoint, and sets the thread running again...  Your "next"
never finishes.

So, on to the patch itself.

I've split the breakpoint object in two.  One bit
holds the lowest level aspects of the breakpoint --- the
address, the shadow memory of the breakpoint, and whether
the trap is presently planted in the inferior.  I've
called this the raw breakpoint.  The other object is a bit
higher level, it represents the GDBserver internal
breakpoint, and this is simply called a breakpoint.
Each instance of this object holds one reference to a
raw breakpoint.  Multiple breakpoints may hold references
to the same raw breakpoint.  There's never more than
one raw breakpoint for the same address.  raw breakpoints
are then reference counted.

I think that at some point, we'll want to split the
breakpoint object out of mem-break.c, so that we can
have GDBserver internal breakpoints not backed by
memory breakpoints, but instead handled by the target's
debug API.  I've not attempted at this, it seems much
more work for no gain at present.

I didn't enable Z0 on other linux archs since
they don't actually need it, and, other targets would need
more work.  E.g., ARM would have to be taught to insert
ARM, Thumb, or Thumb-2 breakpoints, while presently, it
only knows how to insert one of those (for the thread
event breakpoint, in the C library, which is usually
ARM), and with recent kernels with clone events support,
it doesn't need any at all.

This is the pretty part of the story.  The ugly part
is described in the next patch...

-- 
Pedro Alves

2010-03-26  Pedro Alves  <pedro@codesourcery.com>

	gdb/gdbserver/
	* linux-low.c (linux_wait_1): Avoid setting need_step_over is
	there's a GDB breakpoint at stop_pc.  Always report a trap to GDB
	if we could tell there's a GDB breakpoint at stop_pc.
	(need_step_over_p): Don't do a step over if we find a GDB
	breakpoint at the resume PC.

	* mem-break.c (struct raw_breakpoint): New.
	(enum bkpt_type): New type `gdb_breakpoint'.
	(struct breakpoint): Delete the `PC', `old_data' and `inserted'
	fields.  New field `raw'.
	(find_raw_breakpoint_at): New.
	(set_raw_breakpoint_at): Handle refcounting.  Create a raw
	breakpoint instead.
	(set_breakpoint_at): Adjust.
	(delete_raw_breakpoint): New.
	(release_breakpoint): New.
	(delete_breakpoint): Rename to...
	(delete_breakpoint_1): ... this.  Add proc parameter.  Use
	release_breakpoint.  Return ENOENT.
	(delete_breakpoint): Reimplement.
	(find_breakpoint_at): Delete.
	(find_gdb_breakpoint_at): New.
	(delete_breakpoint_at): Delete.
	(set_gdb_breakpoint_at): New.
	(delete_gdb_breakpoint_at): New.
	(gdb_breakpoint_here): New.
	(set_reinsert_breakpoint): Use release_breakpoint.
	(uninsert_breakpoint): Rename to ...
	(uninsert_raw_breakpoint): ... this.
	(uninsert_breakpoints_at): Adjust to handle raw breakpoints.
	(reinsert_raw_breakpoint): Change parameter type to
	raw_breakpoint.
	(reinsert_breakpoints_at): Adjust to handle raw breakpoints
	instead.
	(check_breakpoints): Adjust.  Use release_breakpoint.
	(breakpoint_here): Rewrite using find_raw_breakpoint_at.
	(breakpoint_inserted_here): Ditto.
	(check_mem_read): Adjust to iterate over raw breakpoints instead.
	Don't trust the breakpoint's shadow if it is not inserted.
	(check_mem_write): Adjust to iterate over raw breakpoints instead.
	(delete_all_breakpoints): Adjust.
	(free_all_breakpoints): Mark all breakpoints as uninserted, and
	use delete_breakpoint_1.

	* mem-break.h (breakpoints_supported): Delete declaration.
	(set_gdb_breakpoint_at): Declare.
	(gdb_breakpoint_here): Declare.
	(delete_breakpoint_at): Delete.
	(delete_gdb_breakpoint_at): Declare.

	* server.h (struct raw_breakpoint): Forward declare.
	(struct process_info): New field `raw_breakpoints'.

	* linux-x86-low.c (x86_insert_point, x86_remote_point): Handle Z0
	breakpoints.

---
 gdb/gdbserver/linux-low.c     |   56 +++++--
 gdb/gdbserver/linux-x86-low.c |    4 
 gdb/gdbserver/mem-break.c     |  322 ++++++++++++++++++++++++++++++++----------
 gdb/gdbserver/mem-break.h     |   15 +
 gdb/gdbserver/server.h        |    4 
 5 files changed, 305 insertions(+), 96 deletions(-)

Index: src/gdb/gdbserver/linux-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-low.c	2010-03-26 00:17:11.000000000 +0000
+++ src/gdb/gdbserver/linux-low.c	2010-03-26 15:40:08.000000000 +0000
@@ -1740,7 +1740,8 @@ retry:
 	  if (debug_threads)
 	    fprintf (stderr, "Hit a gdbserver breakpoint.\n");
 
-	  event_child->need_step_over = 1;
+	  if (breakpoint_here (event_child->stop_pc))
+	    event_child->need_step_over = 1;
 	}
     }
   else
@@ -1755,11 +1756,18 @@ retry:
 
   /* Check If GDB would be interested in this event.  If GDB wanted
      this thread to single step, we always want to report the SIGTRAP,
-     and let GDB handle it.  */
+     and let GDB handle it.  Watchpoints should always be reported.
+     So should signals we can't explain.  A SIGTRAP we can't explain
+     could be a GDB breakpoint --- we may or not support Z0
+     breakpoints.  If we do, we're be able to handle GDB breakpoints
+     on top of internal breakpoints, by handling the 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
 		   || event_child->last_resume_kind == resume_step
 		   || event_child->stopped_by_watchpoint
-		   || (!step_over_finished && !bp_explains_trap));
+		   || (!step_over_finished && !bp_explains_trap)
+		   || gdb_breakpoint_here (event_child->stop_pc));
 
   /* We found no reason GDB would want us to stop.  We either hit one
      of our own breakpoints, or finished an internal step GDB
@@ -1801,6 +1809,8 @@ retry:
 	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))
+	fprintf (stderr, "Stopped by GDB breakpoint.\n");
       if (debug_threads)
 	fprintf (stderr, "Hit a non-gdbserver trap event.\n");
     }
@@ -2401,21 +2411,37 @@ need_step_over_p (struct inferior_list_e
   saved_inferior = current_inferior;
   current_inferior = get_lwp_thread (lwp);
 
-  /* We only step over our breakpoints.  */
+  /* We can only step over breakpoints we know about.  */
   if (breakpoint_here (pc))
     {
-      if (debug_threads)
-	fprintf (stderr,
-		 "Need step over [LWP %ld]? yes, found breakpoint at 0x%s\n",
-		 lwpid_of (lwp), paddress (pc));
-
-      /* We've found an lwp that needs stepping over --- return 1 so
-	 that find_inferior stops looking.  */
-      current_inferior = saved_inferior;
+      /* Don't step over a breakpoint that GDB expects to hit
+	 though.  */
+      if (gdb_breakpoint_here (pc))
+	{
+	  if (debug_threads)
+	    fprintf (stderr,
+		     "Need step over [LWP %ld]? yes, but found"
+		     " GDB breakpoint at 0x%s; skipping step over\n",
+		     lwpid_of (lwp), paddress (pc));
 
-      /* If the step over is cancelled, this is set again.  */
-      lwp->need_step_over = 0;
-      return 1;
+	  current_inferior = saved_inferior;
+	  return 0;
+	}
+      else
+	{
+	  if (debug_threads)
+	    fprintf (stderr,
+		     "Need step over [LWP %ld]? yes, found breakpoint at 0x%s\n",
+		     lwpid_of (lwp), paddress (pc));
+
+	  /* We've found an lwp that needs stepping over --- return 1 so
+	     that find_inferior stops looking.  */
+	  current_inferior = saved_inferior;
+
+	  /* If the step over is cancelled, this is set again.  */
+	  lwp->need_step_over = 0;
+	  return 1;
+	}
     }
 
   current_inferior = saved_inferior;
Index: src/gdb/gdbserver/mem-break.c
===================================================================
--- src.orig/gdb/gdbserver/mem-break.c	2010-03-26 00:17:11.000000000 +0000
+++ src/gdb/gdbserver/mem-break.c	2010-03-26 18:07:34.000000000 +0000
@@ -26,9 +26,53 @@ int breakpoint_len;
 
 #define MAX_BREAKPOINT_LEN 8
 
+/* GDB will never try to install multiple breakpoints at the same
+   address.  But, we need to keep track of internal breakpoints too,
+   and so we do need to be able to install multiple breakpoints at the
+   same address transparently.  We keep track of two different, and
+   closely related structures.  A raw breakpoint, which manages the
+   low level, close to the metal aspect of a breakpoint.  It holds the
+   breakpoint address, and a buffer holding a copy of the instructions
+   that would be in memory had not been a breakpoint there (we call
+   that the shadow memory of the breakpoint).  We occasionally need to
+   temporarilly uninsert a breakpoint without the client knowing about
+   it (e.g., to step over an internal breakpoint), so we keep an
+   `inserted' state associated with this low level breakpoint
+   structure.  There can only be one such object for a given address.
+   Then, we have (a bit higher level) breakpoints.  This structure
+   holds a callback to be called whenever a breakpoint is hit, a
+   high-level type, and a link to a low level raw breakpoint.  There
+   can be many high-level breakpoints at the same address, and all of
+   them will point to the same raw breakpoint, which is reference
+   counted.  */
+
+/* The low level, physical, raw breakpoint.  */
+struct raw_breakpoint
+{
+  struct raw_breakpoint *next;
+
+  /* A reference count.  Each high level breakpoint referencing this
+     raw breakpoint accounts for one reference.  */
+  int refcount;
+
+  /* The breakpoint's insertion address.  There can only be one raw
+     breakpoint for a given PC.  */
+  CORE_ADDR pc;
+
+  /* The breakpoint's shadow memory.  */
+  unsigned char old_data[MAX_BREAKPOINT_LEN];
+
+  /* Non-zero if this breakpoint is currently inserted in the
+     inferior.  */
+  int inserted;
+};
+
 /* The type of a breakpoint.  */
 enum bkpt_type
   {
+    /* A GDB breakpoint, requested with a Z0 packet.  */
+    gdb_breakpoint,
+
     /* A basic-software-single-step breakpoint.  */
     reinsert_breakpoint,
 
@@ -37,38 +81,57 @@ enum bkpt_type
     other_breakpoint,
   };
 
+/* A high level (in gdbserver's perspective) breakpoint.  */
 struct breakpoint
 {
   struct breakpoint *next;
-  CORE_ADDR pc;
-  unsigned char old_data[MAX_BREAKPOINT_LEN];
-
-  /* Non-zero if this breakpoint is currently inserted in the
-     inferior.  */
-  int inserted;
 
   /* The breakpoint's type.  */
   enum bkpt_type type;
 
+  /* Link to this breakpoint's raw breakpoint.  This is always
+     non-NULL.  */
+  struct raw_breakpoint *raw;
+
   /* Function to call when we hit this breakpoint.  If it returns 1,
-     the breakpoint shall be deleted; 0, it will be left inserted.  */
+     the breakpoint shall be deleted; 0 or if this callback is NULL,
+     it will be left inserted.  */
   int (*handler) (CORE_ADDR);
 };
 
-static void uninsert_breakpoint (struct breakpoint *bp);
+static struct raw_breakpoint *
+find_raw_breakpoint_at (CORE_ADDR where)
+{
+  struct process_info *proc = current_process ();
+  struct raw_breakpoint *bp;
 
-static struct breakpoint *
+  for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
+    if (bp->pc == where)
+      return bp;
+
+  return NULL;
+}
+
+static struct raw_breakpoint *
 set_raw_breakpoint_at (CORE_ADDR where)
 {
   struct process_info *proc = current_process ();
-  struct breakpoint *bp;
+  struct raw_breakpoint *bp;
   int err;
 
   if (breakpoint_data == NULL)
     error ("Target does not support breakpoints.");
 
+  bp = find_raw_breakpoint_at (where);
+  if (bp != NULL)
+    {
+      bp->refcount++;
+      return bp;
+    }
+
   bp = xcalloc (1, sizeof (*bp));
   bp->pc = where;
+  bp->refcount = 1;
 
   err = (*the_target->read_memory) (where, bp->old_data,
 				    breakpoint_len);
@@ -97,8 +160,8 @@ set_raw_breakpoint_at (CORE_ADDR where)
 
   /* Link the breakpoint in.  */
   bp->inserted = 1;
-  bp->next = proc->breakpoints;
-  proc->breakpoints = bp;
+  bp->next = proc->raw_breakpoints;
+  proc->raw_breakpoints = bp;
   return bp;
 }
 
@@ -107,10 +170,11 @@ set_breakpoint_at (CORE_ADDR where, int 
 {
   struct process_info *proc = current_process ();
   struct breakpoint *bp;
+  struct raw_breakpoint *raw;
 
-  bp = set_raw_breakpoint_at (where);
+  raw = set_raw_breakpoint_at (where);
 
-  if (bp == NULL)
+  if (raw == NULL)
     {
       /* warn? */
       return NULL;
@@ -118,6 +182,8 @@ set_breakpoint_at (CORE_ADDR where, int 
 
   bp = xcalloc (1, sizeof (struct breakpoint));
   bp->type = other_breakpoint;
+
+  bp->raw = raw;
   bp->handler = handler;
 
   bp->next = proc->breakpoints;
@@ -126,11 +192,84 @@ set_breakpoint_at (CORE_ADDR where, int 
   return bp;
 }
 
-static void
-delete_breakpoint (struct breakpoint *todel)
+static int
+delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel)
+{
+  struct raw_breakpoint *bp, **bp_link;
+  int ret;
+
+  bp = proc->raw_breakpoints;
+  bp_link = &proc->raw_breakpoints;
+
+  while (bp)
+    {
+      if (bp == todel)
+	{
+	  if (bp->inserted)
+	    {
+	      struct raw_breakpoint *prev_bp_link = *bp_link;
+
+	      *bp_link = bp->next;
+
+	      ret = (*the_target->write_memory) (bp->pc, bp->old_data,
+						 breakpoint_len);
+	      if (ret != 0)
+		{
+		  /* Something went wrong, relink the breakpoint.  */
+		  *bp_link = prev_bp_link;
+
+		  if (debug_threads)
+		    fprintf (stderr,
+			     "Failed to uninsert raw breakpoint "
+			     "at 0x%s (%s) while deleting it.\n",
+			     paddress (bp->pc), strerror (ret));
+		  return ret;
+		}
+
+	    }
+	  else
+	    *bp_link = bp->next;
+
+	  free (bp);
+	  return 0;
+	}
+      else
+	{
+	  bp_link = &bp->next;
+	  bp = *bp_link;
+	}
+    }
+
+  warning ("Could not find raw breakpoint in list.");
+  return ENOENT;
+}
+
+static int
+release_breakpoint (struct process_info *proc, struct breakpoint *bp)
+{
+  int newrefcount;
+  int ret;
+
+  newrefcount = bp->raw->refcount - 1;
+  if (newrefcount == 0)
+    {
+      ret = delete_raw_breakpoint (proc, bp->raw);
+      if (ret != 0)
+	return ret;
+    }
+  else
+    bp->raw->refcount = newrefcount;
+
+  free (bp);
+
+  return 0;
+}
+
+static int
+delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel)
 {
-  struct process_info *proc = current_process ();
   struct breakpoint *bp, **bp_link;
+  int err;
 
   bp = proc->breakpoints;
   bp_link = &proc->breakpoints;
@@ -141,9 +280,12 @@ delete_breakpoint (struct breakpoint *to
 	{
 	  *bp_link = bp->next;
 
-	  uninsert_breakpoint (bp);
-	  free (bp);
-	  return;
+	  err = release_breakpoint (proc, bp);
+	  if (err != 0)
+	    return err;
+
+	  bp = *bp_link;
+	  return 0;
 	}
       else
 	{
@@ -153,30 +295,71 @@ delete_breakpoint (struct breakpoint *to
     }
 
   warning ("Could not find breakpoint in list.");
+  return ENOENT;
+}
+
+static int
+delete_breakpoint (struct breakpoint *todel)
+{
+  struct process_info *proc = current_process ();
+  return delete_breakpoint_1 (proc, todel);
 }
 
 static struct breakpoint *
-find_breakpoint_at (CORE_ADDR where)
+find_gdb_breakpoint_at (CORE_ADDR where)
 {
   struct process_info *proc = current_process ();
-  struct breakpoint *bp = proc->breakpoints;
+  struct breakpoint *bp;
 
-  while (bp != NULL)
-    {
-      if (bp->pc == where)
-	return bp;
-      bp = bp->next;
-    }
+  for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
+    if (bp->type == gdb_breakpoint && bp->raw->pc == where)
+      return bp;
 
   return NULL;
 }
 
-void
-delete_breakpoint_at (CORE_ADDR addr)
+int
+set_gdb_breakpoint_at (CORE_ADDR where)
 {
-  struct breakpoint *bp = find_breakpoint_at (addr);
-  if (bp != NULL)
-    delete_breakpoint (bp);
+  struct breakpoint *bp;
+
+  if (breakpoint_data == NULL)
+    return 1;
+
+  bp = set_breakpoint_at (where, NULL);
+  if (bp == NULL)
+    return -1;
+
+  bp->type = gdb_breakpoint;
+  return 0;
+}
+
+int
+delete_gdb_breakpoint_at (CORE_ADDR addr)
+{
+  struct breakpoint *bp;
+  int err;
+
+  if (breakpoint_data == NULL)
+    return 1;
+
+  bp = find_gdb_breakpoint_at (addr);
+  if (bp == NULL)
+    return -1;
+
+  err = delete_breakpoint (bp);
+  if (err)
+    return -1;
+
+  return 0;
+}
+
+int
+gdb_breakpoint_here (CORE_ADDR where)
+{
+  struct breakpoint *bp = find_gdb_breakpoint_at (where);
+
+  return (bp != NULL);
 }
 
 void
@@ -185,7 +368,6 @@ set_reinsert_breakpoint (CORE_ADDR stop_
   struct breakpoint *bp;
 
   bp = set_breakpoint_at (stop_at, NULL);
-
   bp->type = reinsert_breakpoint;
 }
 
@@ -203,13 +385,7 @@ delete_reinsert_breakpoints (void)
       if (bp->type == reinsert_breakpoint)
 	{
 	  *bp_link = bp->next;
-
-	  /* If something goes wrong, maybe this is a shared library
-	     breakpoint, and the shared library has been unmapped.
-	     Assume the breakpoint is gone anyway.  */
-	  uninsert_breakpoint (bp);
-	  free (bp);
-
+	  release_breakpoint (proc, bp);
 	  bp = *bp_link;
 	}
       else
@@ -221,7 +397,7 @@ delete_reinsert_breakpoints (void)
 }
 
 static void
-uninsert_breakpoint (struct breakpoint *bp)
+uninsert_raw_breakpoint (struct raw_breakpoint *bp)
 {
   if (bp->inserted)
     {
@@ -245,9 +421,9 @@ uninsert_breakpoint (struct breakpoint *
 void
 uninsert_breakpoints_at (CORE_ADDR pc)
 {
-  struct breakpoint *bp;
+  struct raw_breakpoint *bp;
 
-  bp = find_breakpoint_at (pc);
+  bp = find_raw_breakpoint_at (pc);
   if (bp == NULL)
     {
       /* This can happen when we remove all breakpoints while handling
@@ -261,11 +437,11 @@ uninsert_breakpoints_at (CORE_ADDR pc)
     }
 
   if (bp->inserted)
-    uninsert_breakpoint (bp);
+    uninsert_raw_breakpoint (bp);
 }
 
 static void
-reinsert_raw_breakpoint (struct breakpoint *bp)
+reinsert_raw_breakpoint (struct raw_breakpoint *bp)
 {
   int err;
 
@@ -285,16 +461,16 @@ reinsert_raw_breakpoint (struct breakpoi
 void
 reinsert_breakpoints_at (CORE_ADDR pc)
 {
-  struct breakpoint *bp;
+  struct raw_breakpoint *bp;
 
-  bp = find_breakpoint_at (pc);
+  bp = find_raw_breakpoint_at (pc);
   if (bp == NULL)
     {
       /* This can happen when we remove all breakpoints while handling
 	 a step-over.  */
       if (debug_threads)
 	fprintf (stderr,
-		 "Could not find breakpoint at 0x%s "
+		 "Could not find raw breakpoint at 0x%s "
 		 "in list (reinserting).\n",
 		 paddress (pc));
       return;
@@ -314,9 +490,9 @@ check_breakpoints (CORE_ADDR stop_pc)
 
   while (bp)
     {
-      if (bp->pc == stop_pc)
+      if (bp->raw->pc == stop_pc)
 	{
-	  if (!bp->inserted)
+	  if (!bp->raw->inserted)
 	    {
 	      warning ("Hit a removed breakpoint?");
 	      return;
@@ -326,7 +502,7 @@ check_breakpoints (CORE_ADDR stop_pc)
 	    {
 	      *bp_link = bp->next;
 
-	      delete_breakpoint (bp);
+	      release_breakpoint (proc, bp);
 
 	      bp = *bp_link;
 	      continue;
@@ -348,34 +524,24 @@ set_breakpoint_data (const unsigned char
 int
 breakpoint_here (CORE_ADDR addr)
 {
-  struct process_info *proc = current_process ();
-  struct breakpoint *bp;
-
-  for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
-    if (bp->pc == addr)
-      return 1;
-
-  return 0;
+  return (find_raw_breakpoint_at (addr) != NULL);
 }
 
 int
 breakpoint_inserted_here (CORE_ADDR addr)
 {
-  struct process_info *proc = current_process ();
-  struct breakpoint *bp;
+  struct raw_breakpoint *bp;
 
-  for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
-    if (bp->pc == addr && bp->inserted)
-      return 1;
+  bp = find_raw_breakpoint_at (addr);
 
-  return 0;
+  return (bp != NULL && bp->inserted);
 }
 
 void
 check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
 {
   struct process_info *proc = current_process ();
-  struct breakpoint *bp = proc->breakpoints;
+  struct raw_breakpoint *bp = proc->raw_breakpoints;
   CORE_ADDR mem_end = mem_addr + mem_len;
 
   for (; bp != NULL; bp = bp->next)
@@ -401,7 +567,8 @@ check_mem_read (CORE_ADDR mem_addr, unsi
       copy_offset = start - bp->pc;
       buf_offset = start - mem_addr;
 
-      memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
+      if (bp->inserted)
+	memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
     }
 }
 
@@ -409,7 +576,7 @@ void
 check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
 {
   struct process_info *proc = current_process ();
-  struct breakpoint *bp = proc->breakpoints;
+  struct raw_breakpoint *bp = proc->raw_breakpoints;
   CORE_ADDR mem_end = mem_addr + mem_len;
 
   for (; bp != NULL; bp = bp->next)
@@ -449,7 +616,7 @@ delete_all_breakpoints (void)
   struct process_info *proc = current_process ();
 
   while (proc->breakpoints)
-    delete_breakpoint (proc->breakpoints);
+    delete_breakpoint_1 (proc, proc->breakpoints);
 }
 
 /* Release all breakpoints, but do not try to un-insert them from the
@@ -458,12 +625,15 @@ delete_all_breakpoints (void)
 void
 free_all_breakpoints (struct process_info *proc)
 {
-  struct breakpoint *bp;
+  struct raw_breakpoint *raw_bp;
 
+  for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next)
+    raw_bp->inserted = 0;
+
+  /* Note: use PROC explicitly instead of deferring to
+     delete_all_breakpoints --- CURRENT_INFERIOR may already have been
+     released when we get here.  There should be no call to
+     current_process from here on.  */
   while (proc->breakpoints)
-    {
-      bp = proc->breakpoints;
-      proc->breakpoints = bp->next;
-      free (bp);
-    }
+    delete_breakpoint_1 (proc, proc->breakpoints);
 }
Index: src/gdb/gdbserver/mem-break.h
===================================================================
--- src.orig/gdb/gdbserver/mem-break.h	2010-03-26 00:17:11.000000000 +0000
+++ src/gdb/gdbserver/mem-break.h	2010-03-26 17:38:36.000000000 +0000
@@ -25,9 +25,10 @@
 /* Breakpoints are opaque.  */
 struct breakpoint;
 
-/* Returns TRUE if breakpoints are supported on this target.  */
+/* Create a new GDB breakpoint at WHERE.  Returns -1 if breakpoints
+   are not supported on this target, 0 otherwise.  */
 
-int breakpoints_supported (void);
+int set_gdb_breakpoint_at (CORE_ADDR where);
 
 /* Returns TRUE if there's any breakpoint at ADDR in our tables,
    inserted, or not.  */
@@ -38,6 +39,10 @@ int breakpoint_here (CORE_ADDR addr);
 
 int breakpoint_inserted_here (CORE_ADDR addr);
 
+/* Returns TRUE if there's a GDB breakpoint set at ADDR.  */
+
+int gdb_breakpoint_here (CORE_ADDR where);
+
 /* Create a new breakpoint at WHERE, and call HANDLER when
    it is hit.  HANDLER should return 1 if the breakpoint
    should be deleted, 0 otherwise.  */
@@ -45,10 +50,10 @@ int breakpoint_inserted_here (CORE_ADDR 
 struct breakpoint *set_breakpoint_at (CORE_ADDR where,
 				      int (*handler) (CORE_ADDR));
 
-/* Delete a breakpoint previously inserted at ADDR with
-   set_breakpoint_at.  */
+/* Delete a GDB breakpoint previously inserted at ADDR with
+   set_gdb_breakpoint_at.  */
 
-void delete_breakpoint_at (CORE_ADDR addr);
+int delete_gdb_breakpoint_at (CORE_ADDR addr);
 
 /* Set a reinsert breakpoint at STOP_AT.  */
 
Index: src/gdb/gdbserver/server.h
===================================================================
--- src.orig/gdb/gdbserver/server.h	2010-03-26 00:17:11.000000000 +0000
+++ src/gdb/gdbserver/server.h	2010-03-26 00:17:37.000000000 +0000
@@ -191,6 +191,7 @@ struct dll_info
 
 struct sym_cache;
 struct breakpoint;
+struct raw_breakpoint;
 struct process_info_private;
 
 struct process_info
@@ -209,6 +210,9 @@ struct process_info
   /* The list of memory breakpoints.  */
   struct breakpoint *breakpoints;
 
+  /* The list of raw memory breakpoints.  */
+  struct raw_breakpoint *raw_breakpoints;
+
   /* Private target data.  */
   struct process_info_private *private;
 };
Index: src/gdb/gdbserver/linux-x86-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-x86-low.c	2010-03-26 15:35:58.000000000 +0000
+++ src/gdb/gdbserver/linux-x86-low.c	2010-03-26 15:39:45.000000000 +0000
@@ -431,6 +431,8 @@ x86_insert_point (char type, CORE_ADDR a
   struct process_info *proc = current_process ();
   switch (type)
     {
+    case '0':
+      return set_gdb_breakpoint_at (addr);
     case '2':
     case '3':
     case '4':
@@ -448,6 +450,8 @@ x86_remove_point (char type, CORE_ADDR a
   struct process_info *proc = current_process ();
   switch (type)
     {
+    case '0':
+      return delete_gdb_breakpoint_at (addr);
     case '2':
     case '3':
     case '4':


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