public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFA] Implement support for PowerPC BookE ranged breakpoints
@ 2011-01-28  1:54 Thiago Jung Bauermann
  2011-01-28  9:39 ` Eli Zaretskii
  2011-02-17 15:49 ` Ulrich Weigand
  0 siblings, 2 replies; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-01-28  1:54 UTC (permalink / raw)
  To: gdb-patches ml

Hi all,

This is (finally!) the last patch in my series to support BookE hardware
debug features. It adds the following command:

(gdb) help break-range 
Set a breakpoint for an address range.
break-range START-LOCATION, END-LOCATION
where START-LOCATION and END-LOCATION can be one of the following:
  LINENUM, for that line in the current file,
  FILE:LINENUM, for that line in that file,
  +OFFSET, for that number of lines after the current line
           or the start of the range
  FUNCTION, for the first line in that function,
  FILE:FUNCTION, to distinguish among like-named static functions.
  *ADDRESS, for the instruction at that address.

The breakpoint will stop execution of the inferior whenever it
executes any address within the [start-address, end-address] range
(including START-LOCATION and END-LOCATION).

This patch needs a doc review.

There are no regressions on ppc-linux, ppc64-linux and i386-linux. Ok?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-01-27  Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

	Implement support for PowerPC BookE ranged breakpoints.

gdb/
	* NEWS: Mention support for ranged breakpoints on embedded
	PowerPC.
	* breakpoint.h (struct ui_stream): Add opaque declaration.
	(struct bp_target_info) <length>: New member variable.
	(struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
	instead of struct breakpoint as argument, and also add ASPACE
	and BP_ADDR arguments.  Update all callers.
	(struct breakpoint_ops) <print_it>: Take struct bp_location
	instead of struct breakpoint as argument.  Update all callers.
	(struct breakpoint_ops) <print_one>: Add WRAP_INDENT and STB
	arguments.  Update all callers.
	(struct breakpoint_ops) <print_mention>: Add SAY_WHERE argument.
	Update all callers.
	* breakpoint.c (breakpoint_address_match_range): Add function
	prototype.
	(is_ranged_breakpoint): Likewise.
	(insert_bp_location): Set bl->target_info.length.
	(breakpoint_here_p): Check for address match for in ranged
	breakpoints.
	(print_it_typical): Move NULL check from here...
	(print_bp_stop_message): ... to here.
	(bpstat_check_location): Move call to
	breakpoint_ops.breakpoint_hit to the top.
	(breakpoint_address_match_range): New function.
	(hw_breakpoint_used_count): Count resources used by all locations
	in a breakpoint, and use breakpoint_ops.resources_needed if
	available.
	(breakpoint_hit_ranged_breakpoint): New function.
	(resources_needed_ranged_breakpoint): Likewise.
	(print_it_ranged_breakpoint): Likewise.
	(print_one_ranged_breakpoint): Likewise.
	(print_one_detail_ranged_breakpoint): Likewise.
	(print_mention_ranged_breakpoint): Likewise.
	(print_recreate_ranged_breakpoint): Likewise.
	(ranged_breakpoint_ops): New structure.
	(is_ranged_breakpoint): New function.
	(break_range_command): Likewise.
	(_initialize_breakpoint): Register break-range command.
	* ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
	function.
	(ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
	(ppc_linux_remove_hw_breakpoint): Likewise.
	(_initialize_ppc_linux_nat): Initialize
	to_ranged_break_num_registers.
	* target.c (update_current_target): Add comment about
	to_ranged_break_num_registers.
	(target_ranged_break_num_registers): New function.
	* target.h (struct target_ops) <to_ranged_break_num_registers>:
	New method.
	(target_ranged_break_num_registers): Add function prototype.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	(ui_out_field_range_core_addr): Add function prototype.

gdb/doc/
	* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index d5d15ec..0a5d82d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -131,6 +131,12 @@
   by the inferior against the watchpoint address.  See the "PowerPC Embedded"
   section in the user manual for more details.
 
+* When locally debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
+  which stop execution of the inferior whenever it executes any address
+  within the specified range.  See the "PowerPC Embedded" section in the
+  user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 2fda77f..7eedc0a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10875,20 +10875,23 @@ print_recreate_exception (enum exception_catchpoint_kind ex,
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
+print_it_catch_exception (const struct bp_location *bl,
+			  const struct value *old_val)
 {
-  return print_it_exception (ex_catch_exception, b);
+  return print_it_exception (ex_catch_exception, bl->owner);
 }
 
 static void
-print_one_catch_exception (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_exception (struct breakpoint *b, struct bp_location **last_loc,
+			   char *wrap_indent, struct ui_stream *stb)
 {
   print_one_exception (ex_catch_exception, b, last_loc);
 }
 
 static void
-print_mention_catch_exception (struct breakpoint *b)
+print_mention_catch_exception (struct breakpoint *b, int *say_where)
 {
+  *say_where = 0;
   print_mention_exception (ex_catch_exception, b);
 }
 
@@ -10915,22 +10918,24 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b,
+print_it_catch_exception_unhandled (const struct bp_location *bl,
 				    const struct value *old_val)
 {
-  return print_it_exception (ex_catch_exception_unhandled, b);
+  return print_it_exception (ex_catch_exception_unhandled, bl->owner);
 }
 
 static void
 print_one_catch_exception_unhandled (struct breakpoint *b,
-				     struct bp_location **last_loc)
+				     struct bp_location **last_loc,
+				     char *wrap_indent, struct ui_stream *stb)
 {
   print_one_exception (ex_catch_exception_unhandled, b, last_loc);
 }
 
 static void
-print_mention_catch_exception_unhandled (struct breakpoint *b)
+print_mention_catch_exception_unhandled (struct breakpoint *b, int *say_where)
 {
+  *say_where = 0;
   print_mention_exception (ex_catch_exception_unhandled, b);
 }
 
@@ -10957,20 +10962,23 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
+print_it_catch_assert (const struct bp_location *bl,
+		       const struct value *old_val)
 {
-  return print_it_exception (ex_catch_assert, b);
+  return print_it_exception (ex_catch_assert, bl->owner);
 }
 
 static void
-print_one_catch_assert (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_assert (struct breakpoint *b, struct bp_location **last_loc,
+			char *wrap_indent, struct ui_stream *stb)
 {
   print_one_exception (ex_catch_assert, b, last_loc);
 }
 
 static void
-print_mention_catch_assert (struct breakpoint *b)
+print_mention_catch_assert (struct breakpoint *b, int *say_where)
 {
+  *say_where = 0;
   print_mention_exception (ex_catch_assert, b);
 }
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 7eef1b4..b939b6f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -128,6 +128,11 @@ static int breakpoint_address_match (struct address_space *aspace1,
 static int watchpoint_locations_match (struct bp_location *loc1,
 				       struct bp_location *loc2);
 
+static int breakpoint_address_match_range (struct address_space *aspace1,
+					   CORE_ADDR addr1, CORE_ADDR len1,
+					   struct address_space *aspace2,
+					   CORE_ADDR addr2);
+
 static void breakpoints_info (char *, int);
 
 static void watchpoints_info (char *, int);
@@ -222,6 +227,8 @@ static void trace_pass_command (char *, int);
 
 static int is_masked_watchpoint (const struct breakpoint *b);
 
+static int is_ranged_breakpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1644,6 +1651,7 @@ insert_bp_location (struct bp_location *bl,
   memset (&bl->target_info, 0, sizeof (bl->target_info));
   bl->target_info.placed_address = bl->address;
   bl->target_info.placed_address_space = bl->pspace->aspace;
+  bl->target_info.length = bl->length;
 
   if (bl->loc_type == bp_loc_software_breakpoint
       || bl->loc_type == bp_loc_hardware_breakpoint)
@@ -2771,11 +2779,15 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
 	  && bl->loc_type != bp_loc_hardware_breakpoint)
 	continue;
 
-      /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL.  */
+      /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL.  */
       if ((breakpoint_enabled (bl->owner)
 	   || bl->owner->enable_state == bp_permanent)
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && (breakpoint_address_match (bl->pspace->aspace, bl->address,
+					aspace, pc)
+	       || (is_ranged_breakpoint (bl->owner)
+		   && breakpoint_address_match_range (bl->pspace->aspace,
+						      bl->address, bl->length,
+						      aspace, pc))))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -3306,11 +3318,6 @@ print_it_typical (bpstat bs)
   int bp_temp = 0;
   enum print_stop_action result;
 
-  /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
-     which has since been deleted.  */
-  if (bs->breakpoint_at == NULL)
-    return PRINT_UNKNOWN;
-
   gdb_assert (bs->bp_location_at != NULL);
 
   bl = bs->bp_location_at;
@@ -3516,11 +3523,15 @@ print_bp_stop_message (bpstat bs)
       {
 	struct breakpoint *b = bs->breakpoint_at;
 
+	/* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+	   which has since been deleted.  */
+	if (b == NULL)
+	  return PRINT_UNKNOWN;
+
 	/* Normal case.  Call the breakpoint's print_it method, or
 	   print_it_typical.  */
-	/* FIXME: how breakpoint can ever be NULL here?  */
-	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b, bs->old_val);
+	if (b->ops != NULL && b->ops->print_it != NULL)
+	  return b->ops->print_it (bs->bp_location_at, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3855,6 +3866,9 @@ bpstat_check_location (const struct bp_location *bl,
   /* BL is from existing struct breakpoint.  */
   gdb_assert (b != NULL);
 
+  if (b->ops && b->ops->breakpoint_hit)
+    return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+
   /* By definition, the inferior does not report stops at
      tracepoints.  */
   if (is_tracepoint (b))
@@ -3883,7 +3897,7 @@ bpstat_check_location (const struct bp_location *bl,
   if (is_hardware_watchpoint (b)
       && b->watchpoint_triggered == watch_triggered_no)
     return 0;
-  
+
   if (b->type == bp_hardware_breakpoint)
     {
       if (bl->address != bp_addr)
@@ -3894,13 +3908,6 @@ bpstat_check_location (const struct bp_location *bl,
 	return 0;
     }
 
-  if (b->type == bp_catchpoint)
-    {
-      gdb_assert (b->ops != NULL && b->ops->breakpoint_hit != NULL);
-      if (!b->ops->breakpoint_hit (b))
-        return 0;
-    }
-     
   return 1;
 }
 
@@ -4775,7 +4782,7 @@ print_one_breakpoint_location (struct breakpoint *b,
 	 calling it here is not likely to get any nice result.  So,
 	 make sure there's just one location.  */
       gdb_assert (b->loc == NULL || b->loc->next == NULL);
-      b->ops->print_one (b, last_loc);
+      b->ops->print_one (b, last_loc, wrap_indent, stb);
     }
   else
     switch (b->type)
@@ -5467,6 +5474,21 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
 	  && addr1 == addr2);
 }
 
+/* Returns true if {ASPACE2,ADDR2} falls within the range determined by
+   {ASPACE1,ADDR1,LEN1}.  In most targets, this can only be true if ASPACE1
+   matches ASPACE2.  On targets that have global breakpoints, the address
+   space doesn't really matter.  */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+				CORE_ADDR len1, struct address_space *aspace2,
+				CORE_ADDR addr2)
+{
+  return ((gdbarch_has_global_breakpoints (target_gdbarch)
+	   || aspace1 == aspace2)
+	  && addr2 >= addr1 && addr2 < addr1 + len1);
+}
+
 /* Assuming LOC1 and LOC2's types' have meaningful target addresses
    (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
    represent the same location.  */
@@ -6084,17 +6106,20 @@ remove_catch_fork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_fork (struct breakpoint *b)
+breakpoint_hit_catch_fork (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_forked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for fork
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
+print_it_catch_fork (const struct bp_location *bl, const struct value *old_val)
 {
+  const struct breakpoint *b = bl->owner;
+
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
 		   b->number, ptid_get_pid (b->forked_inferior_pid));
@@ -6105,7 +6130,8 @@ print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
    catchpoints.  */
 
 static void
-print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc,
+		      char *wrap_indent, struct ui_stream *stb)
 {
   struct value_print_options opts;
 
@@ -6131,8 +6157,9 @@ print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
    catchpoints.  */
 
 static void
-print_mention_catch_fork (struct breakpoint *b)
+print_mention_catch_fork (struct breakpoint *b, int *say_where)
 {
+  *say_where = 0;
   printf_filtered (_("Catchpoint %d (fork)"), b->number);
 }
 
@@ -6183,17 +6210,20 @@ remove_catch_vfork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_vfork (struct breakpoint *b)
+breakpoint_hit_catch_vfork (const struct bp_location *bl,
+			    struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_vforked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for vfork
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
+print_it_catch_vfork (const struct bp_location *bl, const struct value *old_val)
 {
+  const struct breakpoint *b = bl->owner;
+
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
 		   b->number, ptid_get_pid (b->forked_inferior_pid));
@@ -6204,7 +6234,8 @@ print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
    catchpoints.  */
 
 static void
-print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc,
+		       char *wrap_indent, struct ui_stream *stb)
 {
   struct value_print_options opts;
 
@@ -6229,8 +6260,9 @@ print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
    catchpoints.  */
 
 static void
-print_mention_catch_vfork (struct breakpoint *b)
+print_mention_catch_vfork (struct breakpoint *b, int *say_where)
 {
+  *say_where = 0;
   printf_filtered (_("Catchpoint %d (vfork)"), b->number);
 }
 
@@ -6344,12 +6376,14 @@ remove_catch_syscall (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_syscall (struct breakpoint *b)
+breakpoint_hit_catch_syscall (const struct bp_location *bl,
+			      struct address_space *aspace, CORE_ADDR bp_addr)
 {
   /* We must check if we are catching specific syscalls in this
      breakpoint.  If we are, then we must guarantee that the called
      syscall is the same syscall we are catching.  */
   int syscall_number = 0;
+  const struct breakpoint *b = bl->owner;
 
   if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
     return 0;
@@ -6376,7 +6410,8 @@ breakpoint_hit_catch_syscall (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
+print_it_catch_syscall (const struct bp_location *bl,
+			const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6387,6 +6422,7 @@ print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
   struct syscall s;
   struct cleanup *old_chain;
   char *syscall_id;
+  const struct breakpoint *b = bl->owner;
 
   get_last_target_status (&ptid, &last);
 
@@ -6417,8 +6453,8 @@ print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
    catchpoints.  */
 
 static void
-print_one_catch_syscall (struct breakpoint *b,
-                         struct bp_location **last_loc)
+print_one_catch_syscall (struct breakpoint *b, struct bp_location **last_loc,
+			 char *wrap_indent, struct ui_stream *stb)
 {
   struct value_print_options opts;
 
@@ -6472,8 +6508,10 @@ print_one_catch_syscall (struct breakpoint *b,
    catchpoints.  */
 
 static void
-print_mention_catch_syscall (struct breakpoint *b)
+print_mention_catch_syscall (struct breakpoint *b, int *say_where)
 {
+  *say_where = 0;
+
   if (b->syscalls_to_be_caught)
     {
       int i, iter;
@@ -6636,14 +6674,17 @@ remove_catch_exec (struct bp_location *bl)
 }
 
 static int
-breakpoint_hit_catch_exec (struct breakpoint *b)
+breakpoint_hit_catch_exec (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_execd (inferior_ptid, &b->exec_pathname);
+  return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
+print_it_catch_exec (const struct bp_location *bl, const struct value *old_val)
 {
+  const struct breakpoint *b = bl->owner;
+
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
 		   b->exec_pathname);
@@ -6651,7 +6692,8 @@ print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 }
 
 static void
-print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc,
+		      char *wrap_indent, struct ui_stream *stb)
 {
   struct value_print_options opts;
 
@@ -6673,8 +6715,9 @@ print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
 }
 
 static void
-print_mention_catch_exec (struct breakpoint *b)
+print_mention_catch_exec (struct breakpoint *b, int *say_where)
 {
+  *say_where = 0;
   printf_filtered (_("Catchpoint %d (exec)"), b->number);
 }
 
@@ -6720,13 +6763,22 @@ create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
 static int
 hw_breakpoint_used_count (void)
 {
-  struct breakpoint *b;
   int i = 0;
+  struct breakpoint *b;
+  struct bp_location *bl;
 
   ALL_BREAKPOINTS (b)
   {
     if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
-      i++;
+      for (bl = b->loc; bl; bl = bl->next)
+	{
+	  /* Special types of hardware breakpoints may use more than
+	     one register.  */
+	  if (b->ops && b->ops->resources_needed)
+	    i += b->ops->resources_needed (bl);
+	  else
+	    i++;
+	}
   }
 
   return i;
@@ -6948,7 +7000,7 @@ mention (struct breakpoint *b)
   observer_notify_breakpoint_created (b->number);
 
   if (b->ops != NULL && b->ops->print_mention != NULL)
-    b->ops->print_mention (b);
+    b->ops->print_mention (b, &say_where);
   else
     switch (b->type)
       {
@@ -8192,6 +8244,329 @@ stopat_command (char *arg, int from_tty)
     break_command_1 (arg, 0, from_tty);
 }
 
+/* Implement the "breakpoint_hit" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+				  struct address_space *aspace,
+				  CORE_ADDR bp_addr)
+{
+  return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+					 bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+  return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (const struct bp_location *bl,
+			    const struct value *old_val)
+{
+  const struct breakpoint *b = bl->owner;
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  gdb_assert (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint);
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  if (bl->address != bl->requested_address)
+    breakpoint_adjustment_warning (bl->requested_address,
+				   bl->address,
+				   b->number, 1);
+  annotate_breakpoint (b->number);
+  if (b->disposition == disp_del)
+    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+  else if (b->type == bp_hardware_breakpoint)
+    ui_out_text (uiout, "\nHardware assisted ranged breakpoint ");
+  else
+    ui_out_text (uiout, "\nRanged breakpoint ");
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+    }
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
+
+  do_cleanups (old_chain);
+
+  return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+			     struct bp_location **last_loc,
+			     char *wrap_indent, struct ui_stream *stb)
+{
+  struct value_print_options opts;
+
+  /* We're prepared to deal with only one location.  */
+  gdb_assert (b->loc && !b->loc->next);
+
+  get_user_print_options (&opts);
+
+  if (opts.addressprint)
+    ui_out_field_skip (uiout, "addr");
+  annotate_field (5);
+  if (b->loc->enabled)
+    print_breakpoint_location (b, b->loc, wrap_indent, stb);
+  if (b->loc)
+    *last_loc = b->loc;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  gdb_assert (b->loc);
+
+  ui_out_text (uiout, "\taddress range: ");
+  ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+				b->loc->address, b->loc->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b, int *say_where)
+{
+  switch (b->type)
+    {
+    case bp_breakpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	{
+	  *say_where = 0;
+	  break;
+	}
+      if (b->disposition == disp_del)
+	printf_filtered (_("Temporary ranged breakpoint"));
+      else
+	printf_filtered (_("Ranged breakpoint"));
+      printf_filtered (_(" %d"), b->number);
+      *say_where = 1;
+      break;
+    case bp_hardware_breakpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	{
+	  *say_where = 0;
+	  break;
+	}
+
+      printf_filtered (_("Hardware assisted ranged breakpoint %d"), b->number);
+      *say_where = 1;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("Invalid breakpoint type."));
+    }
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  fprintf_unfiltered (fp, "break-range %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints.  */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+  NULL, /* insert */
+  NULL, /* remove */
+  breakpoint_hit_ranged_breakpoint,
+  resources_needed_ranged_breakpoint,
+  NULL, /* works_in_software_mode */
+  print_it_ranged_breakpoint,
+  print_one_ranged_breakpoint,
+  print_one_detail_ranged_breakpoint,
+  print_mention_ranged_breakpoint,
+  print_recreate_ranged_breakpoint
+};
+
+/* Tell whether the given breakpoint is a ranged breakpoint.  */
+
+static int
+is_ranged_breakpoint (const struct breakpoint *b)
+{
+  return b->ops == &ranged_breakpoint_ops;
+}
+
+/* Implement the "break-range" CLI command.  */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+  char *orig_arg;
+  char **addr_string_start;
+  int bp_count, can_use_bp, ret;
+  CORE_ADDR start_addr, start, end;
+  LONGEST length;
+  struct breakpoint *b;
+  struct symtabs_and_lines sals_start, sals_end;
+  struct gdbarch *gdbarch = get_current_arch ();
+  struct gdb_exception e;
+  struct cleanup *cleanup_start, *cleanup_end, *cleanup_orig_arg;
+
+  /* We don't support software ranged breakpoints.  */
+  if (target_ranged_break_num_registers () < 0)
+    error (_("This target does not support hardware ranged breakpoints."));
+
+  bp_count = hw_breakpoint_used_count ();
+  bp_count += target_ranged_break_num_registers ();
+  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+						   bp_count, 0);
+  if (can_use_bp < 0)
+    error (_("Hardware breakpoints used exceeds limit."));
+
+  if (arg == NULL || arg[0] == '\0')
+    error(_("No address range specified."));
+
+  /* Save the original argument string for later use by
+     print_recreate_ranged_hw_breakpoint.  */
+  orig_arg = xstrdup (arg);
+  /* We'll only dispose of it if this function is aborted.  */
+  cleanup_orig_arg = make_cleanup (xfree, orig_arg);
+
+  sals_start.sals = NULL;
+  sals_start.nelts = 0;
+  addr_string_start = NULL;
+
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  /* We need to use parse_to_comma_and_eval but decode_line_1 uses
+     parse_and_eval_address_1 (see decode_indirect), so we just call it
+     directly if the user provided an explicit PC.  */
+  if (arg[0] == '*')
+    {
+      arg++;
+      start_addr = value_as_address (parse_to_comma_and_eval (&arg));
+
+      sals_start.sals = (struct symtab_and_line *)
+	xmalloc (sizeof (struct symtab_and_line));
+      sals_start.nelts = 1;
+      sals_start.sals[0] = find_pc_line (start_addr, 0);
+      sals_start.sals[0].pc = start_addr;
+      sals_start.sals[0].section = find_pc_overlay (start_addr);
+      sals_start.sals[0].explicit_pc = 1;
+
+      cleanup_start = make_cleanup (xfree, sals_start.sals);
+    }
+  else
+    {
+
+      parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
+
+      cleanup_start = make_cleanup (xfree, sals_start.sals);
+      make_cleanup (xfree, addr_string_start);
+      make_cleanup (xfree, addr_string_start[0]);
+    }
+
+  if (arg[0] != ',')
+    error (_("Too few arguments."));
+  else if (sals_start.nelts == 0)
+    error (_("Could not find location of the beginning of the range."));
+  else if (sals_start.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  breakpoint_sals_to_pc (&sals_start);
+  start_addr = sals_start.sals[0].pc;
+
+  arg++;	/* Skip the comma.  */
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  /* Parse the end location.  */
+
+  sals_end.sals = NULL;
+  sals_end.nelts = 0;
+
+  sals_end = decode_line_1 (&arg, 1, sals_start.sals[0].symtab,
+			    sals_start.sals[0].line, 0, 0);
+
+  cleanup_end = make_cleanup (xfree, sals_end.sals);
+
+  if (sals_end.nelts == 0)
+    error (_("Could not find location of the end of the range."));
+  else if (sals_end.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  breakpoint_sals_to_pc (&sals_end);
+
+  /* If the user provided a PC value, use it.  Otherwise, find the
+     address of the end of the given location.  */
+  if (sals_end.sals[0].explicit_pc)
+    end = sals_end.sals[0].pc;
+  else
+    {
+      ret = find_line_pc_range (sals_end.sals[0], &start, &end);
+      if (!ret)
+	error (_("Could not find location of the end of the range."));
+
+      /* find_line_pc_range returns the start of the next line.  */
+      end--;
+    }
+
+  if (start_addr > end)
+    error (_("Invalid address range, end preceeds start."));
+
+  length = end - start_addr + 1;
+  if (length == 1)
+    {
+      /* This range is simple enough to be handled by
+	 the `hbreak' command.  */
+      hbreak_command (addr_string_start[0], 1);
+
+      do_cleanups (cleanup_orig_arg);
+
+      return;
+    }
+
+  do_cleanups (cleanup_end);
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sals_start.sals[0], bp_hardware_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = NULL;
+  b->exp_string = orig_arg;
+  b->val = NULL;
+  b->val_valid = 0;
+  b->ops = &ranged_breakpoint_ops;
+  b->loc->length = length;
+
+  do_cleanups (cleanup_start);
+  discard_cleanups (cleanup_orig_arg);
+
+  mention (b);
+  update_global_location_list (1);
+}
+
 /*  Return non-zero if EXP is verified as constant.  Returned zero
     means EXP is variable.  Also the constant detection may fail for
     some constant expressions and in such case still falsely return
@@ -8392,9 +8767,10 @@ works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
    masked hardware watchpoints.  */
 
 static enum print_stop_action
-print_it_masked_watchpoint (struct breakpoint *b,
+print_it_masked_watchpoint (const struct bp_location *bl,
 			    const struct value *old_val)
 {
+  struct breakpoint *b = bl->owner;
   struct ui_stream *stb;
   struct cleanup *old_chain;
 
@@ -8466,10 +8842,12 @@ print_one_detail_masked_watchpoint (const struct breakpoint *b,
    masked hardware watchpoints.  */
 
 static void
-print_mention_masked_watchpoint (struct breakpoint *b)
+print_mention_masked_watchpoint (struct breakpoint *b, int *say_where)
 {
   struct cleanup *ui_out_chain;
 
+  *say_where = 0;
+
   switch (b->type)
     {
     case bp_hardware_watchpoint:
@@ -9292,10 +9670,11 @@ catch_exec_command_1 (char *arg, int from_tty,
 }
 
 static enum print_stop_action
-print_it_exception_catchpoint (struct breakpoint *b,
+print_it_exception_catchpoint (const struct bp_location *bl,
 			       const struct value *old_val)
 {
   int bp_temp, bp_throw;
+  const struct breakpoint *b = bl->owner;
 
   annotate_catchpoint (b->number);
 
@@ -9325,7 +9704,8 @@ print_it_exception_catchpoint (struct breakpoint *b,
 
 static void
 print_one_exception_catchpoint (struct breakpoint *b, 
-				struct bp_location **last_loc)
+				struct bp_location **last_loc,
+				char *wrap_indent, struct ui_stream *stb)
 {
   struct value_print_options opts;
 
@@ -9349,11 +9729,13 @@ print_one_exception_catchpoint (struct breakpoint *b,
 }
 
 static void
-print_mention_exception_catchpoint (struct breakpoint *b)
+print_mention_exception_catchpoint (struct breakpoint *b, int *say_where)
 {
   int bp_temp;
   int bp_throw;
 
+  *say_where = 0;
+
   bp_temp = b->disposition == disp_del;
   bp_throw = strstr (b->addr_string, "throw") != NULL;
   ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
@@ -12830,7 +13212,23 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
 			   &show_always_inserted_mode,
 			   &breakpoint_set_cmdlist,
 			   &breakpoint_show_cmdlist);
-  
+
+  add_com ("break-range", class_breakpoint, break_range_command, _("\
+Set a breakpoint for an address range.\n\
+break-range START-LOCATION, END-LOCATION\n\
+where START-LOCATION and END-LOCATION can be one of the following:\n\
+  LINENUM, for that line in the current file,\n\
+  FILE:LINENUM, for that line in that file,\n\
+  +OFFSET, for that number of lines after the current line\n\
+           or the start of the range\n\
+  FUNCTION, for the first line in that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, for the instruction at that address.\n\
+\n\
+The breakpoint will stop execution of the inferior whenever it\n\
+executes any address within the [start-address, end-address] range\n\
+(including START-LOCATION and END-LOCATION)."));
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 3195124..0b19c35 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -29,6 +29,7 @@ struct value;
 struct block;
 struct breakpoint_object;
 struct ui_out;
+struct ui_stream;
 
 /* This is the maximum number of bytes a breakpoint instruction can
    take.  Feel free to increase it.  It's just used in a few places to
@@ -218,6 +219,10 @@ struct bp_target_info
      is used to determine the type of breakpoint to insert.  */
   CORE_ADDR placed_address;
 
+  /* If this is a ranged breakpoint, then this field contains the
+     length of the range that will be watched for execution.  */
+  ULONGEST length;
+
   /* If the breakpoint lives in memory and reading that memory would
      give back the breakpoint, instead of the original contents, then
      the original contents are cached here.  Only SHADOW_LEN bytes of
@@ -325,8 +330,8 @@ struct bp_location
      bp_loc_other.  */
   CORE_ADDR address;
 
-  /* For hardware watchpoints, the size of data ad ADDRESS being
-     watches.  */
+  /* For hardware watchpoints, the size of the memory region being watched.
+     For hardware ranged breakpoints, the size of the breakpoint range.  */
   int length;
 
   /* Type of hardware watchpoint.  */
@@ -384,7 +389,8 @@ struct breakpoint_ops
 
   /* Return non-zero if the debugger should tell the user that this
      breakpoint was hit.  */
-  int (*breakpoint_hit) (struct breakpoint *);
+  int (*breakpoint_hit) (const struct bp_location *, struct address_space *,
+			 CORE_ADDR);
 
   /* Tell how many hardware resources (debug registers) are needed
      for this breakpoint.  If this function is not provided, then
@@ -398,12 +404,13 @@ struct breakpoint_ops
 
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *,
+  enum print_stop_action (*print_it) (const struct bp_location *,
 				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info
      breakpoints".  */
-  void (*print_one) (struct breakpoint *, struct bp_location **);
+  void (*print_one) (struct breakpoint *, struct bp_location **,
+		     char *wrap_indent, struct ui_stream *);
 
   /* Display extra information about this breakpoint, below the normal
      breakpoint description in "info breakpoints".
@@ -420,8 +427,10 @@ struct breakpoint_ops
   void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
 
   /* Display information about this breakpoint after setting it
-     (roughly speaking; this is called from "mention").  */
-  void (*print_mention) (struct breakpoint *);
+     (roughly speaking; this is called from "mention").  On return,
+     SAY_WHERE will be one if the caller is supposed to print
+     location information about the breakpoint, or zero otherwise.  */
+  void (*print_mention) (struct breakpoint *, int *say_where);
 
   /* Print to FP the CLI command that recreates this breakpoint.  */
   void (*print_recreate) (struct breakpoint *, struct ui_file *fp);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 24d0441..0d0b14c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18724,9 +18724,25 @@ the @code{watch} command (@pxref{Set Watchpoints}), as in:
 (@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
 @end smallexample
 
+PowerPC embedded processors support hardware accelerated ranged breakpoints.
+A @dfn{ranged breakpoint} stops execution of the inferior whenever it
+executes any address within the range it specifies.  To set a ranged
+breakpoint in @value{GDBN}, use the @code{break-range} command.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex break-range
+@item break-range @var{start-location}, @var{end-location}
+Set a breakpoint for an address range.
+@var{start-location} and @var{end-location} can specify a function name,
+a line number, an offset of lines from the current line or from the start
+location, or an address of an instruction (@xref{Specify Location},
+for a list of all the possible ways to specify a @var{location}.)
+The breakpoint will stop execution of the inferior whenever it
+executes any address within the specified range, (including
+@var{start-location} and @var{end-location}.)
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 140ad97..8b5842b 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1637,6 +1637,19 @@ booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
   hw_breaks[i].hw_break = NULL;
 }
 
+/* Return the number of registers needed for a ranged breakpoint.  */
+
+static int
+ppc_linux_ranged_break_num_registers (struct target_ops *target)
+{
+  return ((have_ptrace_booke_interface ()
+	   && booke_debug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
+	  2 : -1);
+}
+
+/* Insert the hardware breakpoint described by BP_TGT.  Returns 0 for
+   success, 1 if hardware breakpoints are not supported or -1 for failure.  */
+
 static int
 ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 				  struct bp_target_info *bp_tgt)
@@ -1650,12 +1663,24 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is
+	 within the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_insert_point (&p, TIDGET (ptid));
 
@@ -1675,12 +1700,24 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is within
+	 the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_remove_point (&p, TIDGET (ptid));
 
@@ -2468,6 +2505,7 @@ _initialize_ppc_linux_nat (void)
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
   t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
+  t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/target.c b/gdb/target.c
index 7a9b3bd..7e54c5e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -598,6 +598,7 @@ update_current_target (void)
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
+      /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
       /* Do not inherit to_insert_mask_watchpoint.  */
@@ -3429,6 +3430,21 @@ target_masked_watch_num_registers (void)
   return return_minus_one ();
 }
 
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_ranged_break_num_registers (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_ranged_break_num_registers != NULL)
+      return t->to_ranged_break_num_registers (t);
+
+  return return_minus_one ();
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
diff --git a/gdb/target.h b/gdb/target.h
index e996272..dec0250 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -448,6 +448,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_ranged_break_num_registers) (struct target_ops *);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -1371,6 +1372,11 @@ extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
 #define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_remove_hw_breakpoint) (gdbarch, bp_tgt)
 
+/* Return number of debug registers needed for a ranged breakpoint,
+   or -1 if ranged breakpoints are not supported.  */
+
+extern int target_ranged_break_num_registers (void);
+
 /* Return non-zero if target knows the data address which triggered this
    target_stopped_by_watchpoint, in such case place it to *ADDR_P.  Only the
    INFERIOR_PTID task is being queried.  */
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 53ad963..97b9df0 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -486,6 +486,50 @@ ui_out_field_fmt_int (struct ui_out *uiout,
   uo_field_int (uiout, fldno, input_width, input_align, fldname, value);
 }
 
+/* Documented in ui-out.h.  */
+
+void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    {
+      address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+      address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+    {
+      strcpy (addstr, "[");
+      strcat (addstr, hex_string_custom (address_start, 8));
+      strcat (addstr, ", ");
+      strcat (addstr, hex_string_custom (address_end, 8));
+      strcat (addstr, "]");
+    }
+  else
+    {
+      strcpy (addstr, "[");
+      strcat (addstr, hex_string_custom (address_start, 16));
+      strcat (addstr, ", ");
+      strcat (addstr, hex_string_custom (address_end, 16));
+      strcat (addstr, "]");
+    }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+/* Documented in ui-out.h.  */
+
 void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 4ad0651..098f1bb 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -113,6 +113,16 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+/* Output a field containing a range of addresses.  */
+
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+					  struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR length);
+
+/* Output a field containing an addresses.  */
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-01-28  1:54 [RFA] Implement support for PowerPC BookE ranged breakpoints Thiago Jung Bauermann
@ 2011-01-28  9:39 ` Eli Zaretskii
  2011-01-31 19:07   ` Thiago Jung Bauermann
  2011-02-17 15:49 ` Ulrich Weigand
  1 sibling, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2011-01-28  9:39 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Date: Thu, 27 Jan 2011 23:26:25 -0200
> 
> This is (finally!) the last patch in my series to support BookE hardware
> debug features. It adds the following command:
> 
> (gdb) help break-range 
> Set a breakpoint for an address range.
> break-range START-LOCATION, END-LOCATION
> where START-LOCATION and END-LOCATION can be one of the following:
>   LINENUM, for that line in the current file,
>   FILE:LINENUM, for that line in that file,
>   +OFFSET, for that number of lines after the current line
>            or the start of the range
>   FUNCTION, for the first line in that function,
>   FILE:FUNCTION, to distinguish among like-named static functions.
>   *ADDRESS, for the instruction at that address.

Thanks.

> +* When locally debugging programs on PowerPC BookE processors running
          ^^^^^^^
You mean "natively", right?  I don't think we use "local debugging"
elsewhere in our documentation, do we?

> +  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
> +  which stop execution of the inferior whenever it executes any address
> +  within the specified range.  See the "PowerPC Embedded" section in the

"whenever it executes an instruction at any address within the
specified range".  (You cannot "execute" an address.)

> +      if (b->disposition == disp_del)
> +	printf_filtered (_("Temporary ranged breakpoint"));
> +      else
> +	printf_filtered (_("Ranged breakpoint"));
> +      printf_filtered (_(" %d"), b->number);

This snippet violates one of the rules of translation-ready software:
don't construct phrases from parts.  I suggest to make " %d" part of
each of the two possibilities.

> +static void
> +print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
> +{
> +  fprintf_unfiltered (fp, "break-range %s", b->exp_string);

Should this string be in _() ?

> +      sals_start.sals = (struct symtab_and_line *)
> +	xmalloc (sizeof (struct symtab_and_line));
> +      sals_start.nelts = 1;

Spaces and TABs mixup alert!

> +The breakpoint will stop execution of the inferior whenever it\n\
> +executes any address within the [start-address, end-address] range\n\
   ^^^^^^^^^^^^^^^^^^^^
Same correction as in NEWS.

> +PowerPC embedded processors support hardware accelerated ranged breakpoints.
> +A @dfn{ranged breakpoint} stops execution of the inferior whenever it

Use @dfn when you first introduce a term, in this case in the previous
sentence.

Also, please add here a @cindex entry about "ranged breakpoint".

> +executes any address within the range it specifies.  To set a ranged
   ^^^^^^^^^^^^^^^^^^^^
Same correction as in NEWS.

> +Set a breakpoint for an address range.
> +@var{start-location} and @var{end-location} can specify a function name,
> +a line number, an offset of lines from the current line or from the start
> +location, or an address of an instruction (@xref{Specify Location},

You want a "see @ref here", not @xref.  The latter will produce "See"
with a capital S, which will look like a typo.  In general, @xref is
supposed to use only at the beginning of a sentence.

> +The breakpoint will stop execution of the inferior whenever it
> +executes any address within the specified range, (including
   ^^^^^^^^^^^^^^^^^^^^
Same correction as above.

The patch for NEWS and the manual is okay with those changes.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-01-28  9:39 ` Eli Zaretskii
@ 2011-01-31 19:07   ` Thiago Jung Bauermann
  2011-01-31 20:39     ` Eli Zaretskii
  0 siblings, 1 reply; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-01-31 19:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Fri, 2011-01-28 at 11:28 +0200, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Date: Thu, 27 Jan 2011 23:26:25 -0200
> Thanks.

Thanks for the review.

> > +* When locally debugging programs on PowerPC BookE processors running
>           ^^^^^^^
> You mean "natively", right?  I don't think we use "local debugging"
> elsewhere in our documentation, do we?

Oops. Fixed.

> > +  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
> > +  which stop execution of the inferior whenever it executes any address
> > +  within the specified range.  See the "PowerPC Embedded" section in the
> 
> "whenever it executes an instruction at any address within the
> specified range".  (You cannot "execute" an address.)

It was an analogy with "read an address" and "write an address", but I
guess even those expressions are not that good. :-) Fixed.

> > +      if (b->disposition == disp_del)
> > +	printf_filtered (_("Temporary ranged breakpoint"));
> > +      else
> > +	printf_filtered (_("Ranged breakpoint"));
> > +      printf_filtered (_(" %d"), b->number);
> 
> This snippet violates one of the rules of translation-ready software:
> don't construct phrases from parts.  I suggest to make " %d" part of
> each of the two possibilities.

Agreed. Fixed.

> > +static void
> > +print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
> > +{
> > +  fprintf_unfiltered (fp, "break-range %s", b->exp_string);
> 
> Should this string be in _() ?

No. This function is called by the "save breakpoints" command an is
expected to write to fp a GDB command which will recreate the
breakpoint.

> > +      sals_start.sals = (struct symtab_and_line *)
> > +	xmalloc (sizeof (struct symtab_and_line));
> > +      sals_start.nelts = 1;
> 
> Spaces and TABs mixup alert!

Hum, I couldn't find the mixup. the lines above and below xmalloc need
to use spaces because they start at column 7. The xmalloc line uses TAB
since it starts at column 9 (and it doesn't have any spaces only one
TAB).

> > +The breakpoint will stop execution of the inferior whenever it\n\
> > +executes any address within the [start-address, end-address] range\n\
>    ^^^^^^^^^^^^^^^^^^^^
> Same correction as in NEWS.

Fixed.

> > +PowerPC embedded processors support hardware accelerated ranged breakpoints.
> > +A @dfn{ranged breakpoint} stops execution of the inferior whenever it
> 
> Use @dfn when you first introduce a term, in this case in the previous
> sentence.

Ok.

> Also, please add here a @cindex entry about "ranged breakpoint".

Done.

> > +executes any address within the range it specifies.  To set a ranged
>    ^^^^^^^^^^^^^^^^^^^^
> Same correction as in NEWS.

Fixed.

> > +Set a breakpoint for an address range.
> > +@var{start-location} and @var{end-location} can specify a function name,
> > +a line number, an offset of lines from the current line or from the start
> > +location, or an address of an instruction (@xref{Specify Location},
> 
> You want a "see @ref here", not @xref.  The latter will produce "See"
> with a capital S, which will look like a typo.  In general, @xref is
> supposed to use only at the beginning of a sentence.

Fixed.

> > +The breakpoint will stop execution of the inferior whenever it
> > +executes any address within the specified range, (including
>    ^^^^^^^^^^^^^^^^^^^^
> Same correction as above.

Fixed.

> The patch for NEWS and the manual is okay with those changes.

Great! The changes will show up next time I post the patch, after the
code review.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-01-31 19:07   ` Thiago Jung Bauermann
@ 2011-01-31 20:39     ` Eli Zaretskii
  0 siblings, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2011-01-31 20:39 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: gdb-patches@sourceware.org
> Date: Mon, 31 Jan 2011 16:59:04 -0200
> 
> > > +  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
> > > +  which stop execution of the inferior whenever it executes any address
> > > +  within the specified range.  See the "PowerPC Embedded" section in the
> > 
> > "whenever it executes an instruction at any address within the
> > specified range".  (You cannot "execute" an address.)
> 
> It was an analogy with "read an address" and "write an address", but I
> guess even those expressions are not that good. :-) Fixed.

"Read from an address" and "write to an address" would be better, yes.

> > > +      sals_start.sals = (struct symtab_and_line *)
> > > +	xmalloc (sizeof (struct symtab_and_line));
> > > +      sals_start.nelts = 1;
> > 
> > Spaces and TABs mixup alert!
> 
> Hum, I couldn't find the mixup. the lines above and below xmalloc need
> to use spaces because they start at column 7. The xmalloc line uses TAB
> since it starts at column 9 (and it doesn't have any spaces only one
> TAB).

Then it's my mixup, sorry.  Disregard that comment.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-01-28  1:54 [RFA] Implement support for PowerPC BookE ranged breakpoints Thiago Jung Bauermann
  2011-01-28  9:39 ` Eli Zaretskii
@ 2011-02-17 15:49 ` Ulrich Weigand
  2011-02-23 20:50   ` Thiago Jung Bauermann
  1 sibling, 1 reply; 22+ messages in thread
From: Ulrich Weigand @ 2011-02-17 15:49 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> This is (finally!) the last patch in my series to support BookE hardware
> debug features. It adds the following command:
> 
> (gdb) help break-range 
> Set a breakpoint for an address range.
> break-range START-LOCATION, END-LOCATION
> where START-LOCATION and END-LOCATION can be one of the following:
>   LINENUM, for that line in the current file,
>   FILE:LINENUM, for that line in that file,
>   +OFFSET, for that number of lines after the current line
>            or the start of the range
>   FUNCTION, for the first line in that function,
>   FILE:FUNCTION, to distinguish among like-named static functions.
>   *ADDRESS, for the instruction at that address.
> 
> The breakpoint will stop execution of the inferior whenever it
> executes any address within the [start-address, end-address] range
> (including START-LOCATION and END-LOCATION).

The user interface for this command seems fine to me.

A couple of detail comments:


> @@ -2771,11 +2779,15 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
>  	  && bl->loc_type != bp_loc_hardware_breakpoint)
>  	continue;
>  
> -      /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL.  */
> +      /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL.  */
>        if ((breakpoint_enabled (bl->owner)
>  	   || bl->owner->enable_state == bp_permanent)
> -	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
> -				       aspace, pc))
> +	  && (breakpoint_address_match (bl->pspace->aspace, bl->address,
> +					aspace, pc)
> +	       || (is_ranged_breakpoint (bl->owner)
> +		   && breakpoint_address_match_range (bl->pspace->aspace,
> +						      bl->address, bl->length,
> +						      aspace, pc))))

It might make sense to have a helper routine that does the right 
thing for both breakpoint types by matching an aspace/pc pair
against a breakpoint location ...

More problematically, while you've changed this use of breakpoint_address_match,
there are many more of them in breakpoint.c, and it seems at least some of
those would also need to be updated to handle range breakpoints (what about
the one in breakpoint_thread_match for example?).


> @@ -3306,11 +3318,6 @@ print_it_typical (bpstat bs)
>    int bp_temp = 0;
>    enum print_stop_action result;
>  
> -  /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
> -     which has since been deleted.  */
> -  if (bs->breakpoint_at == NULL)
> -    return PRINT_UNKNOWN;
> -
>    gdb_assert (bs->bp_location_at != NULL);
>  
>    bl = bs->bp_location_at;
> @@ -3516,11 +3523,15 @@ print_bp_stop_message (bpstat bs)
>        {
>  	struct breakpoint *b = bs->breakpoint_at;
>  
> +	/* bs->breakpoint_at can be NULL if it was a momentary breakpoint
> +	   which has since been deleted.  */
> +	if (b == NULL)
> +	  return PRINT_UNKNOWN;
> +
>  	/* Normal case.  Call the breakpoint's print_it method, or
>  	   print_it_typical.  */
> -	/* FIXME: how breakpoint can ever be NULL here?  */

This seems to be an unrelated change, isn't it?


> -	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
> -	  return b->ops->print_it (b, bs->old_val);
> +	if (b->ops != NULL && b->ops->print_it != NULL)
> +	  return b->ops->print_it (bs->bp_location_at, bs->old_val);

I'm not sure this API change is necessary.  Yes, you need to get at
the location to print range breakpoints, but those will always have
exactly one location ...  The print_it routine could instead just
make the same assumption e.g. print_exception_catchpoint already
does, and just access b->loc.


> +/* Implement the "print_it" breakpoint_ops method for
> +   ranged breakpoints.  */
> +
> +static enum print_stop_action
> +print_it_ranged_breakpoint (const struct bp_location *bl,
> +			    const struct value *old_val)
> +{
> +  const struct breakpoint *b = bl->owner;
> +  struct ui_stream *stb;
> +  struct cleanup *old_chain;
> +
> +  gdb_assert (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint);
> +
> +  stb = ui_out_stream_new (uiout);
> +  old_chain = make_cleanup_ui_out_stream_delete (stb);
> +
> +  if (bl->address != bl->requested_address)
> +    breakpoint_adjustment_warning (bl->requested_address,
> +				   bl->address,
> +				   b->number, 1);

Can this happen?  Does it make sense for a range breakpoint to
have its address adjusted?  If so, does that affect the end as well?

> +  annotate_breakpoint (b->number);
> +  if (b->disposition == disp_del)
> +    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
> +  else if (b->type == bp_hardware_breakpoint)
> +    ui_out_text (uiout, "\nHardware assisted ranged breakpoint ");
> +  else
> +    ui_out_text (uiout, "\nRanged breakpoint ");
> +  if (ui_out_is_mi_like_p (uiout))
> +    {
> +      ui_out_field_string (uiout, "reason",
> +		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
> +      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
> +    }
> +  ui_out_field_int (uiout, "bkptno", b->number);
> +  ui_out_text (uiout, ", ");
> +
> +  do_cleanups (old_chain);
> +
> +  return PRINT_SRC_AND_LOC;
> +}


> +/* Implement the "print_one" breakpoint_ops method for
> +   ranged breakpoints.  */
> +
> +static void
> +print_one_ranged_breakpoint (struct breakpoint *b,
> +			     struct bp_location **last_loc,
> +			     char *wrap_indent, struct ui_stream *stb)
> +{
> +  struct value_print_options opts;
> +
> +  /* We're prepared to deal with only one location.  */
> +  gdb_assert (b->loc && !b->loc->next);
> +
> +  get_user_print_options (&opts);
> +
> +  if (opts.addressprint)
> +    ui_out_field_skip (uiout, "addr");
> +  annotate_field (5);
> +  if (b->loc->enabled)
> +    print_breakpoint_location (b, b->loc, wrap_indent, stb);
> +  if (b->loc)
> +    *last_loc = b->loc;
> +}

I don't like the API change just to pass through those variables,
which don't hold any state information and could just as well be
recreated by the print_breakpoint_location routine itself ...


> +/* Implement the "print_mention" breakpoint_ops method for
> +   ranged breakpoints.  */
> +
> +static void
> +print_mention_ranged_breakpoint (struct breakpoint *b, int *say_where)
> +{
> +  switch (b->type)
> +    {
> +    case bp_breakpoint:
> +      if (ui_out_is_mi_like_p (uiout))
> +	{
> +	  *say_where = 0;
> +	  break;
> +	}
> +      if (b->disposition == disp_del)
> +	printf_filtered (_("Temporary ranged breakpoint"));
> +      else
> +	printf_filtered (_("Ranged breakpoint"));
> +      printf_filtered (_(" %d"), b->number);
> +      *say_where = 1;
> +      break;
> +    case bp_hardware_breakpoint:
> +      if (ui_out_is_mi_like_p (uiout))
> +	{
> +	  *say_where = 0;
> +	  break;
> +	}
> +
> +      printf_filtered (_("Hardware assisted ranged breakpoint %d"), b->number);
> +      *say_where = 1;
> +      break;
> +    default:
> +      internal_error (__FILE__, __LINE__, _("Invalid breakpoint type."));
> +    }
> +}

This adds the SAY_WHERE parameter so that the caller will go ahead to
add location information.  However, for a range breakpoint, this will
just be the start of the range, which may or may not be particularly
useful ...   Shouldn't we either:
- output the full range (start and end),  or
- output nothing ... we'll see the actual location where we stopped anyway

(Either way, the API change to add SAY_WHERE is no longer needed.)


> +  /* We need to use parse_to_comma_and_eval but decode_line_1 uses
> +     parse_and_eval_address_1 (see decode_indirect), so we just call it
> +     directly if the user provided an explicit PC.  */
> +  if (arg[0] == '*')
> +    {
> +      arg++;
> +      start_addr = value_as_address (parse_to_comma_and_eval (&arg));
> +
> +      sals_start.sals = (struct symtab_and_line *)
> +	xmalloc (sizeof (struct symtab_and_line));
> +      sals_start.nelts = 1;
> +      sals_start.sals[0] = find_pc_line (start_addr, 0);
> +      sals_start.sals[0].pc = start_addr;
> +      sals_start.sals[0].section = find_pc_overlay (start_addr);
> +      sals_start.sals[0].explicit_pc = 1;
> +
> +      cleanup_start = make_cleanup (xfree, sals_start.sals);
> +    }
> +  else
> +    {
> +
> +      parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
> +
> +      cleanup_start = make_cleanup (xfree, sals_start.sals);
> +      make_cleanup (xfree, addr_string_start);
> +      make_cleanup (xfree, addr_string_start[0]);
> +    }

Hmm.   This should be fixed in decode_line_1 itself.  The routine currently
only says that it allows a trailing "if ...", but it should probably be
modified to also stop parsing at the comma ...


> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 3195124..0b19c35 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -218,6 +219,10 @@ struct bp_target_info
>       is used to determine the type of breakpoint to insert.  */
>    CORE_ADDR placed_address;
>  
> +  /* If this is a ranged breakpoint, then this field contains the
> +     length of the range that will be watched for execution.  */
> +  ULONGEST length;
> +
>    /* If the breakpoint lives in memory and reading that memory would
>       give back the breakpoint, instead of the original contents, then
>       the original contents are cached here.  Only SHADOW_LEN bytes of
> @@ -325,8 +330,8 @@ struct bp_location
>       bp_loc_other.  */
>    CORE_ADDR address;
>  
> -  /* For hardware watchpoints, the size of data ad ADDRESS being
> -     watches.  */
> +  /* For hardware watchpoints, the size of the memory region being watched.
> +     For hardware ranged breakpoints, the size of the breakpoint range.  */
>    int length;

Why is it ULONGEST above, and int here?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-02-17 15:49 ` Ulrich Weigand
@ 2011-02-23 20:50   ` Thiago Jung Bauermann
  2011-02-24 20:45     ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Ulrich Weigand
  2011-02-28 17:08     ` [RFA] Implement support for PowerPC BookE ranged breakpoints Ulrich Weigand
  0 siblings, 2 replies; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-02-23 20:50 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

Hi Ulrich,

On Thu, 2011-02-17 at 16:30 +0100, Ulrich Weigand wrote: 
> Thiago Jung Bauermann wrote:
> The user interface for this command seems fine to me.

Great.

> A couple of detail comments:

Thanks for your review. 

> > @@ -2771,11 +2779,15 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
> >  	  && bl->loc_type != bp_loc_hardware_breakpoint)
> >  	continue;
> >  
> > -      /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL.  */
> > +      /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL.  */
> >        if ((breakpoint_enabled (bl->owner)
> >  	   || bl->owner->enable_state == bp_permanent)
> > -	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
> > -				       aspace, pc))
> > +	  && (breakpoint_address_match (bl->pspace->aspace, bl->address,
> > +					aspace, pc)
> > +	       || (is_ranged_breakpoint (bl->owner)
> > +		   && breakpoint_address_match_range (bl->pspace->aspace,
> > +						      bl->address, bl->length,
> > +						      aspace, pc))))
> 
> It might make sense to have a helper routine that does the right 
> thing for both breakpoint types by matching an aspace/pc pair
> against a breakpoint location ...

Agreed. I did that.

> More problematically, while you've changed this use of breakpoint_address_match,
> there are many more of them in breakpoint.c, and it seems at least some of
> those would also need to be updated to handle range breakpoints (what about
> the one in breakpoint_thread_match for example?).

I reviewed all the callers of breakpoint_address_match. There are some
places that need to check for ranged breakpoints and others that don't,
so I didn't change all callers to use breakpoint_location_address_match
although that would be harmless (I didn't want to touch more code than
necessary, should I change all callers for consistency?).

The ones I changed to call breakpoint_location_address_match are:

breakpoint_here_p, moribund_breakpoint_here_p,
regular_breakpoint_inserted_here_p, breakpoint_thread_match and
bpstat_stop_status.

Additionally, I changed breakpoint_locations_match to compare the
bp_location.length of the two locations as well, and changed
update_breakpoint_locations to call breakpoint_locations_match instead
of calling breakpoint_address_match directly.

The callers of breakpoint_address_match that I didn't change are:

breakpoint_restore_shadows (only software breakpoints have shadow
contents), bpstat_check_location (it calls ops->breakpoint_hit if
available, which will do the right thing for the bp_location at hand),
single_step_breakpoint_inserted_here_p (it calls
breakpoint_address_match for something which isn't a bp_location, also a
comment there says it checks only software breakpoints). 

> > @@ -3306,11 +3318,6 @@ print_it_typical (bpstat bs)
> >    int bp_temp = 0;
> >    enum print_stop_action result;
> >  
> > -  /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
> > -     which has since been deleted.  */
> > -  if (bs->breakpoint_at == NULL)
> > -    return PRINT_UNKNOWN;
> > -
> >    gdb_assert (bs->bp_location_at != NULL);
> >  
> >    bl = bs->bp_location_at;
> > @@ -3516,11 +3523,15 @@ print_bp_stop_message (bpstat bs)
> >        {
> >  	struct breakpoint *b = bs->breakpoint_at;
> >  
> > +	/* bs->breakpoint_at can be NULL if it was a momentary breakpoint
> > +	   which has since been deleted.  */
> > +	if (b == NULL)
> > +	  return PRINT_UNKNOWN;
> > +
> >  	/* Normal case.  Call the breakpoint's print_it method, or
> >  	   print_it_typical.  */
> > -	/* FIXME: how breakpoint can ever be NULL here?  */
> 
> This seems to be an unrelated change, isn't it?

I consider it to be related. In this patch series I'm revamping the
breakpoint_ops methods to make them more suitable for implementing
breakpoints and watchpoints. print_it_typical is part of that, so an
improvement in a function which calls the print_it method and
print_it_typcal seemed to have a place in this patch.

I don't mind submitting this in a separate patch if you want. 

> > -	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
> > -	  return b->ops->print_it (b, bs->old_val);
> > +	if (b->ops != NULL && b->ops->print_it != NULL)
> > +	  return b->ops->print_it (bs->bp_location_at, bs->old_val);
> 
> I'm not sure this API change is necessary.  Yes, you need to get at
> the location to print range breakpoints, but those will always have
> exactly one location ...  The print_it routine could instead just
> make the same assumption e.g. print_exception_catchpoint already
> does, and just access b->loc.

I was aiming to change breakpoint_ops in a way that makes it possible to
implement different kinds of breakpoints and watchpoints, so I didn't
want to make assumptions specific to ranged breakpoints. But I adopted
your suggestion in this version. 

> > +/* Implement the "print_it" breakpoint_ops method for
> > +   ranged breakpoints.  */
> > +
> > +static enum print_stop_action
> > +print_it_ranged_breakpoint (const struct bp_location *bl,
> > +			    const struct value *old_val)
> > +{
> > +  const struct breakpoint *b = bl->owner;
> > +  struct ui_stream *stb;
> > +  struct cleanup *old_chain;
> > +
> > +  gdb_assert (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint);
> > +
> > +  stb = ui_out_stream_new (uiout);
> > +  old_chain = make_cleanup_ui_out_stream_delete (stb);
> > +
> > +  if (bl->address != bl->requested_address)
> > +    breakpoint_adjustment_warning (bl->requested_address,
> > +				   bl->address,
> > +				   b->number, 1);
> 
> Can this happen?  Does it make sense for a range breakpoint to
> have its address adjusted?  If so, does that affect the end as well?

I guess not. I carried this code from the earliest versions of this
patch series and didn't notice it was dead code. I removed the check
above, and I also simplified print_mention_ranged_breakpoint and
print_one_ranged_breakpoint. 

> > +/* Implement the "print_one" breakpoint_ops method for
> > +   ranged breakpoints.  */
> > +
> > +static void
> > +print_one_ranged_breakpoint (struct breakpoint *b,
> > +			     struct bp_location **last_loc,
> > +			     char *wrap_indent, struct ui_stream *stb)
> > +{
> > +  struct value_print_options opts;
> > +
> > +  /* We're prepared to deal with only one location.  */
> > +  gdb_assert (b->loc && !b->loc->next);
> > +
> > +  get_user_print_options (&opts);
> > +
> > +  if (opts.addressprint)
> > +    ui_out_field_skip (uiout, "addr");
> > +  annotate_field (5);
> > +  if (b->loc->enabled)
> > +    print_breakpoint_location (b, b->loc, wrap_indent, stb);
> > +  if (b->loc)
> > +    *last_loc = b->loc;
> > +}
> 
> I don't like the API change just to pass through those variables,
> which don't hold any state information and could just as well be
> recreated by the print_breakpoint_location routine itself ...

For stb it seems to be true (I'm not very familiar with GDB's output
mechanisms). Unfortunately wrap_indent can't be recreated.
print_one_breakpoint_location sets it based on its print_address_bits
argument. breakpoint_1 calculates print_address_bits taking into account
all breakpoints which pass the filter it is given, or just one
breakpoint. print_one_ranged_breakpoint and print_breakpoint_location
don't have enough information to make the same calculation that
breakpoint_1 did.

This version of the patch drops the stb argument from the print_one
method, but keeps wrap_indent (I could have exchanged wrap_indent for
print_address_bits too). What do you think? 

> > +/* Implement the "print_mention" breakpoint_ops method for
> > +   ranged breakpoints.  */
> > +
> > +static void
> > +print_mention_ranged_breakpoint (struct breakpoint *b, int *say_where)
> > +{
> > +  switch (b->type)
> > +    {
> > +    case bp_breakpoint:
> > +      if (ui_out_is_mi_like_p (uiout))
> > +	{
> > +	  *say_where = 0;
> > +	  break;
> > +	}
> > +      if (b->disposition == disp_del)
> > +	printf_filtered (_("Temporary ranged breakpoint"));
> > +      else
> > +	printf_filtered (_("Ranged breakpoint"));
> > +      printf_filtered (_(" %d"), b->number);
> > +      *say_where = 1;
> > +      break;
> > +    case bp_hardware_breakpoint:
> > +      if (ui_out_is_mi_like_p (uiout))
> > +	{
> > +	  *say_where = 0;
> > +	  break;
> > +	}
> > +
> > +      printf_filtered (_("Hardware assisted ranged breakpoint %d"), b->number);
> > +      *say_where = 1;
> > +      break;
> > +    default:
> > +      internal_error (__FILE__, __LINE__, _("Invalid breakpoint type."));
> > +    }
> > +}
> 
> This adds the SAY_WHERE parameter so that the caller will go ahead to
> add location information.  However, for a range breakpoint, this will
> just be the start of the range, which may or may not be particularly
> useful ...   Shouldn't we either:
> - output the full range (start and end),  or
> - output nothing ... we'll see the actual location where we stopped anyway
> 
> (Either way, the API change to add SAY_WHERE is no longer needed.)

I think it's useful. You have a point in that it makes more sense to
print the end of the range as well. I'd have to extend struct breakpoint
to save the source file and line number of the end of the range if I
were to print them. I'm not sure it's worth it, so I changed
print_mention_ranged_breakpoint to print only the start and end address
of the range. And dropped the say_where argument. What do you think? 

> > +  /* We need to use parse_to_comma_and_eval but decode_line_1 uses
> > +     parse_and_eval_address_1 (see decode_indirect), so we just call it
> > +     directly if the user provided an explicit PC.  */
> > +  if (arg[0] == '*')
> > +    {
> > +      arg++;
> > +      start_addr = value_as_address (parse_to_comma_and_eval (&arg));
> > +
> > +      sals_start.sals = (struct symtab_and_line *)
> > +	xmalloc (sizeof (struct symtab_and_line));
> > +      sals_start.nelts = 1;
> > +      sals_start.sals[0] = find_pc_line (start_addr, 0);
> > +      sals_start.sals[0].pc = start_addr;
> > +      sals_start.sals[0].section = find_pc_overlay (start_addr);
> > +      sals_start.sals[0].explicit_pc = 1;
> > +
> > +      cleanup_start = make_cleanup (xfree, sals_start.sals);
> > +    }
> > +  else
> > +    {
> > +
> > +      parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
> > +
> > +      cleanup_start = make_cleanup (xfree, sals_start.sals);
> > +      make_cleanup (xfree, addr_string_start);
> > +      make_cleanup (xfree, addr_string_start[0]);
> > +    }
> 
> Hmm.   This should be fixed in decode_line_1 itself.  The routine currently
> only says that it allows a trailing "if ...", but it should probably be
> modified to also stop parsing at the comma ...

Ok. decode_line_1 is pretty important in the breakpoint subsystem so I
was afraid to touch it. I'll submit a separate patch with the fix then.
I changed this patch to use just parse_breakpoint_sals. 

> > diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> > index 3195124..0b19c35 100644
> > --- a/gdb/breakpoint.h
> > +++ b/gdb/breakpoint.h
> > @@ -218,6 +219,10 @@ struct bp_target_info
> >       is used to determine the type of breakpoint to insert.  */
> >    CORE_ADDR placed_address;
> >  
> > +  /* If this is a ranged breakpoint, then this field contains the
> > +     length of the range that will be watched for execution.  */
> > +  ULONGEST length;
> > +
> >    /* If the breakpoint lives in memory and reading that memory would
> >       give back the breakpoint, instead of the original contents, then
> >       the original contents are cached here.  Only SHADOW_LEN bytes of
> > @@ -325,8 +330,8 @@ struct bp_location
> >       bp_loc_other.  */
> >    CORE_ADDR address;
> >  
> > -  /* For hardware watchpoints, the size of data ad ADDRESS being
> > -     watches.  */
> > +  /* For hardware watchpoints, the size of the memory region being watched.
> > +     For hardware ranged breakpoints, the size of the breakpoint range.  */
> >    int length;
> 
> Why is it ULONGEST above, and int here?

I thought ULONGEST made more sense for a length field, but didn't feel
confident enough to change bp_location.length accordingly because I
couldn't audit all uses of a field with such a common name ("length") to
make sure the change in signedness wouldn't have side-effects. So I
compromised. :-)

I changed bp_target_info.length to int in this version.

Here's the new patch. No regressions on ppc-linux and ppc64-linux.

The documentation bits contain the changes from Eli's review and are
already approved.

-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-02-23  Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

	Implement support for PowerPC BookE ranged breakpoints.

gdb/
	* NEWS: Mention support for ranged breakpoints on embedded
	PowerPC.
	* breakpoint.h (struct bp_target_info) <length>: New member
	variable.
	(struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
	instead of struct breakpoint as argument, and also add ASPACE
	and BP_ADDR arguments.  Update all callers.
	(struct breakpoint_ops) <print_one>: Add WRAP_INDENT argument.
	Update all callers.
	* breakpoint.c (breakpoint_location_address_match): Add function
	prototype.
	(insert_bp_location): Set bl->target_info.length.
	(breakpoint_here_p): Call breakpoint_location_address_match.
	(moribund_breakpoint_here_p): Likewise.
	(regular_breakpoint_inserted_here_p): Likewise.
	(breakpoint_thread_match): Likewise.
	(bpstat_stop_status): Likewise.
	(print_it_typical): Move NULL check from here...
	(print_bp_stop_message): ... to here.
	(bpstat_check_location): Move call to
	breakpoint_ops.breakpoint_hit to the top.
	(breakpoint_address_match_range): New function.
	(breakpoint_location_address_match): New function.
	(breakpoint_locations_match): Compare the length field of the
	locations too.
	(hw_breakpoint_used_count): Count resources used by all locations
	in a breakpoint, and use breakpoint_ops.resources_needed if
	available.
	(breakpoint_hit_ranged_breakpoint): New function.
	(resources_needed_ranged_breakpoint): Likewise.
	(print_it_ranged_breakpoint): Likewise.
	(print_one_ranged_breakpoint): Likewise.
	(print_one_detail_ranged_breakpoint): Likewise.
	(print_mention_ranged_breakpoint): Likewise.
	(print_recreate_ranged_breakpoint): Likewise.
	(ranged_breakpoint_ops): New structure.
	(break_range_command): New function.
	(update_breakpoint_locations): Call breakpoint_locations_match
	instead of breakpoint_address_match.
	(_initialize_breakpoint): Register break-range command.
	* ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
	function.
	(ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
	(ppc_linux_remove_hw_breakpoint): Likewise.
	(_initialize_ppc_linux_nat): Initialize
	to_ranged_break_num_registers.
	* target.c (update_current_target): Add comment about
	to_ranged_break_num_registers.
	(target_ranged_break_num_registers): New function.
	* target.h (struct target_ops) <to_ranged_break_num_registers>:
	New method.
	(target_ranged_break_num_registers): Add function prototype.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	(ui_out_field_range_core_addr): Add function prototype.

gdb/doc/
	* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 284071d..df518d8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -153,6 +153,12 @@
   by the inferior against the watchpoint address.  See the "PowerPC Embedded"
   section in the user manual for more details.
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
+  which stop execution of the inferior whenever it executes an instruction
+  at any address within the specified range.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 7bb50a1..daae934 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10898,7 +10898,8 @@ print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 }
 
 static void
-print_one_catch_exception (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_exception (struct breakpoint *b, struct bp_location **last_loc,
+			   char *wrap_indent)
 {
   print_one_exception (ex_catch_exception, b, last_loc);
 }
@@ -10940,7 +10941,8 @@ print_it_catch_exception_unhandled (struct breakpoint *b,
 
 static void
 print_one_catch_exception_unhandled (struct breakpoint *b,
-				     struct bp_location **last_loc)
+				     struct bp_location **last_loc,
+				     char *wrap_indent)
 {
   print_one_exception (ex_catch_exception_unhandled, b, last_loc);
 }
@@ -10980,7 +10982,8 @@ print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 }
 
 static void
-print_one_catch_assert (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_assert (struct breakpoint *b, struct bp_location **last_loc,
+			char *wrap_indent)
 {
   print_one_exception (ex_catch_assert, b, last_loc);
 }
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 4c2f4a1..f4c91b5 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -129,6 +129,10 @@ static int breakpoint_address_match (struct address_space *aspace1,
 static int watchpoint_locations_match (struct bp_location *loc1,
 				       struct bp_location *loc2);
 
+static int breakpoint_location_address_match (struct bp_location *bl,
+					      struct address_space *aspace,
+					      CORE_ADDR addr);
+
 static void breakpoints_info (char *, int);
 
 static void watchpoints_info (char *, int);
@@ -1531,6 +1535,7 @@ insert_bp_location (struct bp_location *bl,
   memset (&bl->target_info, 0, sizeof (bl->target_info));
   bl->target_info.placed_address = bl->address;
   bl->target_info.placed_address_space = bl->pspace->aspace;
+  bl->target_info.length = bl->length;
 
   if (bl->loc_type == bp_loc_software_breakpoint
       || bl->loc_type == bp_loc_hardware_breakpoint)
@@ -2792,11 +2797,10 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
 	  && bl->loc_type != bp_loc_hardware_breakpoint)
 	continue;
 
-      /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL.  */
+      /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL.  */
       if ((breakpoint_enabled (bl->owner)
 	   || bl->owner->enable_state == bp_permanent)
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2821,8 +2825,7 @@ moribund_breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
   int ix;
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
-    if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				  aspace,  pc))
+    if (breakpoint_location_address_match (loc, aspace, pc))
       return 1;
 
   return 0;
@@ -2846,8 +2849,7 @@ regular_breakpoint_inserted_here_p (struct address_space *aspace,
 	continue;
 
       if (bl->inserted
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2964,8 +2966,7 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
 	  && bl->owner->enable_state != bp_permanent)
 	continue;
 
-      if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
-				     aspace, pc))
+      if (!breakpoint_location_address_match (bl, aspace, pc))
 	continue;
 
       if (bl->owner->thread != -1)
@@ -3327,11 +3328,6 @@ print_it_typical (bpstat bs)
   int bp_temp = 0;
   enum print_stop_action result;
 
-  /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
-     which has since been deleted.  */
-  if (bs->breakpoint_at == NULL)
-    return PRINT_UNKNOWN;
-
   gdb_assert (bs->bp_location_at != NULL);
 
   bl = bs->bp_location_at;
@@ -3537,10 +3533,14 @@ print_bp_stop_message (bpstat bs)
       {
 	struct breakpoint *b = bs->breakpoint_at;
 
+	/* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+	   which has since been deleted.  */
+	if (b == NULL)
+	  return PRINT_UNKNOWN;
+
 	/* Normal case.  Call the breakpoint's print_it method, or
 	   print_it_typical.  */
-	/* FIXME: how breakpoint can ever be NULL here?  */
-	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
+	if (b->ops != NULL && b->ops->print_it != NULL)
 	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
@@ -3876,6 +3876,9 @@ bpstat_check_location (const struct bp_location *bl,
   /* BL is from existing struct breakpoint.  */
   gdb_assert (b != NULL);
 
+  if (b->ops && b->ops->breakpoint_hit)
+    return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+
   /* By definition, the inferior does not report stops at
      tracepoints.  */
   if (is_tracepoint (b))
@@ -3904,7 +3907,7 @@ bpstat_check_location (const struct bp_location *bl,
   if (is_hardware_watchpoint (b)
       && b->watchpoint_triggered == watch_triggered_no)
     return 0;
-  
+
   if (b->type == bp_hardware_breakpoint)
     {
       if (bl->address != bp_addr)
@@ -3915,13 +3918,6 @@ bpstat_check_location (const struct bp_location *bl,
 	return 0;
     }
 
-  if (b->type == bp_catchpoint)
-    {
-      gdb_assert (b->ops != NULL && b->ops->breakpoint_hit != NULL);
-      if (!b->ops->breakpoint_hit (b))
-        return 0;
-    }
-     
   return 1;
 }
 
@@ -4278,8 +4274,7 @@ bpstat_stop_status (struct address_space *aspace,
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
     {
-      if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				    aspace, bp_addr))
+      if (breakpoint_location_address_match (loc, aspace, bp_addr))
 	{
 	  bs = bpstat_alloc (loc, &bs_link);
 	  /* For hits of moribund locations, we should just proceed.  */
@@ -4796,7 +4791,7 @@ print_one_breakpoint_location (struct breakpoint *b,
 	 calling it here is not likely to get any nice result.  So,
 	 make sure there's just one location.  */
       gdb_assert (b->loc == NULL || b->loc->next == NULL);
-      b->ops->print_one (b, last_loc);
+      b->ops->print_one (b, last_loc, wrap_indent);
     }
   else
     switch (b->type)
@@ -5495,6 +5490,39 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
 	  && addr1 == addr2);
 }
 
+/* Returns true if {ASPACE2,ADDR2} falls within the range determined by
+   {ASPACE1,ADDR1,LEN1}.  In most targets, this can only be true if ASPACE1
+   matches ASPACE2.  On targets that have global breakpoints, the address
+   space doesn't really matter.  */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+				int len1, struct address_space *aspace2,
+				CORE_ADDR addr2)
+{
+  return ((gdbarch_has_global_breakpoints (target_gdbarch)
+	   || aspace1 == aspace2)
+	  && addr2 >= addr1 && addr2 < addr1 + len1);
+}
+
+/* Returns true if {ASPACE,ADDR} matches the breakpoint BL.  BL may be
+   a ranged breakpoint.  In most targets, a match happens only if ASPACE
+   matches the breakpoint's address space.  On targets that have global
+   breakpoints, the address space doesn't really matter.  */
+
+static int
+breakpoint_location_address_match (struct bp_location *bl,
+				   struct address_space *aspace,
+				   CORE_ADDR addr)
+{
+  return (breakpoint_address_match (bl->pspace->aspace, bl->address,
+				    aspace, addr)
+	  || (bl->length
+	      && breakpoint_address_match_range (bl->pspace->aspace,
+						 bl->address, bl->length,
+						 aspace, addr)));
+}
+
 /* Assuming LOC1 and LOC2's types' have meaningful target addresses
    (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
    represent the same location.  */
@@ -5517,8 +5545,10 @@ breakpoint_locations_match (struct bp_location *loc1,
   else if (hw_point1)
     return watchpoint_locations_match (loc1, loc2);
   else
-    return breakpoint_address_match (loc1->pspace->aspace, loc1->address,
-				     loc2->pspace->aspace, loc2->address);
+    /* We compare bp_location.length in order to cover ranged breakpoints.  */
+    return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
+				     loc2->pspace->aspace, loc2->address)
+	    && loc1->length == loc2->length);
 }
 
 static void
@@ -6125,9 +6155,10 @@ remove_catch_fork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_fork (struct breakpoint *b)
+breakpoint_hit_catch_fork (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_forked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for fork
@@ -6146,7 +6177,8 @@ print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
    catchpoints.  */
 
 static void
-print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc,
+		      char *wrap_indent)
 {
   struct value_print_options opts;
 
@@ -6224,9 +6256,10 @@ remove_catch_vfork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_vfork (struct breakpoint *b)
+breakpoint_hit_catch_vfork (const struct bp_location *bl,
+			    struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_vforked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for vfork
@@ -6245,7 +6278,8 @@ print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
    catchpoints.  */
 
 static void
-print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc,
+		       char *wrap_indent)
 {
   struct value_print_options opts;
 
@@ -6385,12 +6419,14 @@ remove_catch_syscall (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_syscall (struct breakpoint *b)
+breakpoint_hit_catch_syscall (const struct bp_location *bl,
+			      struct address_space *aspace, CORE_ADDR bp_addr)
 {
   /* We must check if we are catching specific syscalls in this
      breakpoint.  If we are, then we must guarantee that the called
      syscall is the same syscall we are catching.  */
   int syscall_number = 0;
+  const struct breakpoint *b = bl->owner;
 
   if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
     return 0;
@@ -6459,7 +6495,7 @@ print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 
 static void
 print_one_catch_syscall (struct breakpoint *b,
-                         struct bp_location **last_loc)
+			 struct bp_location **last_loc, char *wrap_indent)
 {
   struct value_print_options opts;
 
@@ -6677,9 +6713,10 @@ remove_catch_exec (struct bp_location *bl)
 }
 
 static int
-breakpoint_hit_catch_exec (struct breakpoint *b)
+breakpoint_hit_catch_exec (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_execd (inferior_ptid, &b->exec_pathname);
+  return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
 }
 
 static enum print_stop_action
@@ -6692,7 +6729,8 @@ print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 }
 
 static void
-print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc,
+		      char *wrap_indent)
 {
   struct value_print_options opts;
 
@@ -6761,13 +6799,22 @@ create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
 static int
 hw_breakpoint_used_count (void)
 {
-  struct breakpoint *b;
   int i = 0;
+  struct breakpoint *b;
+  struct bp_location *bl;
 
   ALL_BREAKPOINTS (b)
   {
     if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
-      i++;
+      for (bl = b->loc; bl; bl = bl->next)
+	{
+	  /* Special types of hardware breakpoints may use more than
+	     one register.  */
+	  if (b->ops && b->ops->resources_needed)
+	    i += b->ops->resources_needed (bl);
+	  else
+	    i++;
+	}
   }
 
   return i;
@@ -8226,6 +8273,288 @@ stopat_command (char *arg, int from_tty)
     break_command_1 (arg, 0, from_tty);
 }
 
+/* Implement the "breakpoint_hit" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+				  struct address_space *aspace,
+				  CORE_ADDR bp_addr)
+{
+  return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+					 bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+  return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (struct breakpoint *b,
+			    const struct value *old_val)
+{
+  struct bp_location *bl = b->loc;
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  annotate_breakpoint (b->number);
+  if (b->disposition == disp_del)
+    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+  else
+    ui_out_text (uiout, "\nHardware assisted ranged breakpoint ");
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+    }
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
+
+  do_cleanups (old_chain);
+
+  return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+			     struct bp_location **last_loc,
+			     char *wrap_indent)
+{
+  struct bp_location *bl = b->loc;
+  struct value_print_options opts;
+  struct ui_stream *stb = ui_out_stream_new (uiout);
+  struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  get_user_print_options (&opts);
+
+  if (opts.addressprint)
+    ui_out_field_skip (uiout, "addr");
+  annotate_field (5);
+  if (bl->enabled)
+    print_breakpoint_location (b, bl, wrap_indent, stb);
+  *last_loc = bl;
+
+  do_cleanups (old_chain);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (bl);
+
+  ui_out_text (uiout, "\taddress range: ");
+  ui_out_field_range_core_addr (uiout, "addr", bl->gdbarch,
+				bl->address, bl->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (bl);
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  if (ui_out_is_mi_like_p (uiout))
+    return;
+
+  printf_filtered (_("Hardware assisted ranged breakpoint %d from %s to %s."),
+		   b->number, paddress (bl->gdbarch, bl->address),
+		   paddress (bl->gdbarch, bl->address + bl->length - 1));
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  fprintf_unfiltered (fp, "break-range %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints.  */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+  NULL, /* insert */
+  NULL, /* remove */
+  breakpoint_hit_ranged_breakpoint,
+  resources_needed_ranged_breakpoint,
+  NULL, /* works_in_software_mode */
+  print_it_ranged_breakpoint,
+  print_one_ranged_breakpoint,
+  print_one_detail_ranged_breakpoint,
+  print_mention_ranged_breakpoint,
+  print_recreate_ranged_breakpoint
+};
+
+/* Implement the "break-range" CLI command.  */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+  char *orig_arg;
+  char **addr_string_start;
+  int bp_count, can_use_bp, ret;
+  CORE_ADDR start_addr, start, end;
+  int length;
+  struct breakpoint *b;
+  struct symtabs_and_lines sals_start, sals_end;
+  struct gdbarch *gdbarch = get_current_arch ();
+  struct gdb_exception e;
+  struct cleanup *cleanup_start, *cleanup_end, *cleanup_orig_arg;
+
+  /* We don't support software ranged breakpoints.  */
+  if (target_ranged_break_num_registers () < 0)
+    error (_("This target does not support hardware ranged breakpoints."));
+
+  bp_count = hw_breakpoint_used_count ();
+  bp_count += target_ranged_break_num_registers ();
+  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+						   bp_count, 0);
+  if (can_use_bp < 0)
+    error (_("Hardware breakpoints used exceeds limit."));
+
+  if (arg == NULL || arg[0] == '\0')
+    error(_("No address range specified."));
+
+  /* Save the original argument string for later use by
+     print_recreate_ranged_hw_breakpoint.  */
+  orig_arg = xstrdup (arg);
+  /* We'll only dispose of it if this function is aborted.  */
+  cleanup_orig_arg = make_cleanup (xfree, orig_arg);
+
+  sals_start.sals = NULL;
+  sals_start.nelts = 0;
+  addr_string_start = NULL;
+
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
+
+  cleanup_start = make_cleanup (xfree, sals_start.sals);
+  make_cleanup (xfree, addr_string_start);
+  make_cleanup (xfree, addr_string_start[0]);
+
+  if (arg[0] != ',')
+    error (_("Too few arguments."));
+  else if (sals_start.nelts == 0)
+    error (_("Could not find location of the beginning of the range."));
+  else if (sals_start.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  breakpoint_sals_to_pc (&sals_start);
+  start_addr = sals_start.sals[0].pc;
+
+  arg++;	/* Skip the comma.  */
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  /* Parse the end location.  */
+
+  sals_end.sals = NULL;
+  sals_end.nelts = 0;
+
+  sals_end = decode_line_1 (&arg, 1, sals_start.sals[0].symtab,
+			    sals_start.sals[0].line, 0, 0);
+
+  cleanup_end = make_cleanup (xfree, sals_end.sals);
+
+  if (sals_end.nelts == 0)
+    error (_("Could not find location of the end of the range."));
+  else if (sals_end.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  breakpoint_sals_to_pc (&sals_end);
+
+  /* If the user provided a PC value, use it.  Otherwise, find the
+     address of the end of the given location.  */
+  if (sals_end.sals[0].explicit_pc)
+    end = sals_end.sals[0].pc;
+  else
+    {
+      ret = find_line_pc_range (sals_end.sals[0], &start, &end);
+      if (!ret)
+	error (_("Could not find location of the end of the range."));
+
+      /* find_line_pc_range returns the start of the next line.  */
+      end--;
+    }
+
+  if (start_addr > end)
+    error (_("Invalid address range, end preceeds start."));
+
+  length = end - start_addr + 1;
+  if (length < 0)
+    /* Length overflowed.  */
+    error (_("Address range too large."));
+  else if (length == 1)
+    {
+      /* This range is simple enough to be handled by
+	 the `hbreak' command.  */
+      hbreak_command (addr_string_start[0], 1);
+
+      do_cleanups (cleanup_orig_arg);
+
+      return;
+    }
+
+  do_cleanups (cleanup_end);
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sals_start.sals[0], bp_hardware_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = NULL;
+  b->exp_string = orig_arg;
+  b->val = NULL;
+  b->val_valid = 0;
+  b->ops = &ranged_breakpoint_ops;
+  b->loc->length = length;
+
+  do_cleanups (cleanup_start);
+  discard_cleanups (cleanup_orig_arg);
+
+  mention (b);
+  update_global_location_list (1);
+}
+
 /*  Return non-zero if EXP is verified as constant.  Returned zero
     means EXP is variable.  Also the constant detection may fail for
     some constant expressions and in such case still falsely return
@@ -9348,7 +9677,8 @@ print_it_exception_catchpoint (struct breakpoint *b,
 
 static void
 print_one_exception_catchpoint (struct breakpoint *b, 
-				struct bp_location **last_loc)
+				struct bp_location **last_loc,
+				char *wrap_indent)
 {
   struct value_print_options opts;
 
@@ -10722,8 +11052,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	    if (have_ambiguous_names)
 	      {
 		for (; l; l = l->next)
-		  if (breakpoint_address_match (e->pspace->aspace, e->address,
-						l->pspace->aspace, l->address))
+		  if (breakpoint_locations_match (e, l))
 		    {
 		      l->enabled = 0;
 		      break;
@@ -12845,7 +13174,23 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
 			   &show_always_inserted_mode,
 			   &breakpoint_set_cmdlist,
 			   &breakpoint_show_cmdlist);
-  
+
+  add_com ("break-range", class_breakpoint, break_range_command, _("\
+Set a breakpoint for an address range.\n\
+break-range START-LOCATION, END-LOCATION\n\
+where START-LOCATION and END-LOCATION can be one of the following:\n\
+  LINENUM, for that line in the current file,\n\
+  FILE:LINENUM, for that line in that file,\n\
+  +OFFSET, for that number of lines after the current line\n\
+           or the start of the range\n\
+  FUNCTION, for the first line in that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, for the instruction at that address.\n\
+\n\
+The breakpoint will stop execution of the inferior whenever it executes\n\
+an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
+range (including START-LOCATION and END-LOCATION)."));
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index ac9872d..a37ded7 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -218,6 +218,10 @@ struct bp_target_info
      is used to determine the type of breakpoint to insert.  */
   CORE_ADDR placed_address;
 
+  /* If this is a ranged breakpoint, then this field contains the
+     length of the range that will be watched for execution.  */
+  int length;
+
   /* If the breakpoint lives in memory and reading that memory would
      give back the breakpoint, instead of the original contents, then
      the original contents are cached here.  Only SHADOW_LEN bytes of
@@ -326,7 +330,8 @@ struct bp_location
   CORE_ADDR address;
 
   /* For hardware watchpoints, the size of the memory region being
-     watched.  */
+     watched.  For hardware ranged breakpoints, the size of the
+     breakpoint range.  */
   int length;
 
   /* Type of hardware watchpoint.  */
@@ -384,7 +389,8 @@ struct breakpoint_ops
 
   /* Return non-zero if the debugger should tell the user that this
      breakpoint was hit.  */
-  int (*breakpoint_hit) (struct breakpoint *);
+  int (*breakpoint_hit) (const struct bp_location *, struct address_space *,
+			 CORE_ADDR);
 
   /* Tell how many hardware resources (debug registers) are needed
      for this breakpoint.  If this function is not provided, then
@@ -403,7 +409,7 @@ struct breakpoint_ops
 
   /* Display information about this breakpoint, for "info
      breakpoints".  */
-  void (*print_one) (struct breakpoint *, struct bp_location **);
+  void (*print_one) (struct breakpoint *, struct bp_location **, char *);
 
   /* Display extra information about this breakpoint, below the normal
      breakpoint description in "info breakpoints".
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 71371e4..77b9ebd 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18755,9 +18755,27 @@ the @code{watch} command (@pxref{Set Watchpoints}), as in:
 (@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
 @end smallexample
 
+@cindex ranged breakpoint
+PowerPC embedded processors support hardware accelerated
+@dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
+the inferior whenever it executes an instruction at any address within
+the range it specifies.  To set a ranged breakpoint in @value{GDBN},
+use the @code{break-range} command.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex break-range
+@item break-range @var{start-location}, @var{end-location}
+Set a breakpoint for an address range.
+@var{start-location} and @var{end-location} can specify a function name,
+a line number, an offset of lines from the current line or from the start
+location, or an address of an instruction (see @ref{Specify Location},
+for a list of all the possible ways to specify a @var{location}.)
+The breakpoint will stop execution of the inferior whenever it
+executes an instruction at any address within the specified range,
+(including @var{start-location} and @var{end-location}.)
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 140ad97..8b5842b 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1637,6 +1637,19 @@ booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
   hw_breaks[i].hw_break = NULL;
 }
 
+/* Return the number of registers needed for a ranged breakpoint.  */
+
+static int
+ppc_linux_ranged_break_num_registers (struct target_ops *target)
+{
+  return ((have_ptrace_booke_interface ()
+	   && booke_debug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
+	  2 : -1);
+}
+
+/* Insert the hardware breakpoint described by BP_TGT.  Returns 0 for
+   success, 1 if hardware breakpoints are not supported or -1 for failure.  */
+
 static int
 ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 				  struct bp_target_info *bp_tgt)
@@ -1650,12 +1663,24 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is
+	 within the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_insert_point (&p, TIDGET (ptid));
 
@@ -1675,12 +1700,24 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is within
+	 the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_remove_point (&p, TIDGET (ptid));
 
@@ -2468,6 +2505,7 @@ _initialize_ppc_linux_nat (void)
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
   t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
+  t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/target.c b/gdb/target.c
index 5afee3c..6686a73 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -598,6 +598,7 @@ update_current_target (void)
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
+      /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
       /* Do not inherit to_insert_mask_watchpoint.  */
@@ -3565,6 +3566,21 @@ target_masked_watch_num_registers (void)
   return return_minus_one ();
 }
 
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_ranged_break_num_registers (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_ranged_break_num_registers != NULL)
+      return t->to_ranged_break_num_registers (t);
+
+  return return_minus_one ();
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
diff --git a/gdb/target.h b/gdb/target.h
index 44c986e..cf6f2e7 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -450,6 +450,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_ranged_break_num_registers) (struct target_ops *);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -1379,6 +1380,11 @@ extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
 #define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_remove_hw_breakpoint) (gdbarch, bp_tgt)
 
+/* Return number of debug registers needed for a ranged breakpoint,
+   or -1 if ranged breakpoints are not supported.  */
+
+extern int target_ranged_break_num_registers (void);
+
 /* Return non-zero if target knows the data address which triggered this
    target_stopped_by_watchpoint, in such case place it to *ADDR_P.  Only the
    INFERIOR_PTID task is being queried.  */
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 53ad963..204a528 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -486,6 +486,50 @@ ui_out_field_fmt_int (struct ui_out *uiout,
   uo_field_int (uiout, fldno, input_width, input_align, fldname, value);
 }
 
+/* Documented in ui-out.h.  */
+
+void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      int length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    {
+      address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+      address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+    {
+      strcpy (addstr, "[");
+      strcat (addstr, hex_string_custom (address_start, 8));
+      strcat (addstr, ", ");
+      strcat (addstr, hex_string_custom (address_end, 8));
+      strcat (addstr, "]");
+    }
+  else
+    {
+      strcpy (addstr, "[");
+      strcat (addstr, hex_string_custom (address_start, 16));
+      strcat (addstr, ", ");
+      strcat (addstr, hex_string_custom (address_end, 16));
+      strcat (addstr, "]");
+    }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+/* Documented in ui-out.h.  */
+
 void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 4ad0651..b540e29 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -113,6 +113,16 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+/* Output a field containing a range of addresses.  */
+
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+					  struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  int length);
+
+/* Output a field containing an addresses.  */
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints)
  2011-02-23 20:50   ` Thiago Jung Bauermann
@ 2011-02-24 20:45     ` Ulrich Weigand
  2011-02-25 14:46       ` Pedro Alves
  2011-02-25 15:33       ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Thiago Jung Bauermann
  2011-02-28 17:08     ` [RFA] Implement support for PowerPC BookE ranged breakpoints Ulrich Weigand
  1 sibling, 2 replies; 22+ messages in thread
From: Ulrich Weigand @ 2011-02-24 20:45 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

I'll get back to you with a full review of the latest patch, I just wanted
to quickly address one specific issue:

> > > +/* Implement the "print_one" breakpoint_ops method for
> > > +   ranged breakpoints.  */
> > > +
> > > +static void
> > > +print_one_ranged_breakpoint (struct breakpoint *b,
> > > +			     struct bp_location **last_loc,
> > > +			     char *wrap_indent, struct ui_stream *stb)
> > > +{
> > > +  struct value_print_options opts;
> > > +
> > > +  /* We're prepared to deal with only one location.  */
> > > +  gdb_assert (b->loc && !b->loc->next);
> > > +
> > > +  get_user_print_options (&opts);
> > > +
> > > +  if (opts.addressprint)
> > > +    ui_out_field_skip (uiout, "addr");
> > > +  annotate_field (5);
> > > +  if (b->loc->enabled)
> > > +    print_breakpoint_location (b, b->loc, wrap_indent, stb);
> > > +  if (b->loc)
> > > +    *last_loc = b->loc;
> > > +}
> > 
> > I don't like the API change just to pass through those variables,
> > which don't hold any state information and could just as well be
> > recreated by the print_breakpoint_location routine itself ...
> 
> For stb it seems to be true (I'm not very familiar with GDB's output
> mechanisms). Unfortunately wrap_indent can't be recreated.
> print_one_breakpoint_location sets it based on its print_address_bits
> argument. breakpoint_1 calculates print_address_bits taking into account
> all breakpoints which pass the filter it is given, or just one
> breakpoint. print_one_ranged_breakpoint and print_breakpoint_location
> don't have enough information to make the same calculation that
> breakpoint_1 did.
> 
> This version of the patch drops the stb argument from the print_one
> method, but keeps wrap_indent (I could have exchanged wrap_indent for
> print_address_bits too). What do you think? 

So the whole point of the wrap_indent is to make sure that if the
description of a breakpoint location is too long to fit into one
line, it is wrapped at the correct point.  That point happens to
be the column named "what" in the breakpoint UI table.

Now the thing is, the UI table layer already knows exactly where
that column starts, so it is kind of pointless to attempt to
re-compute that offset.  In particular, since the code currently
gets it completely wrong anyway: at some point, another column of
variable size was added --see print_type_col_width in breakpoint_1--
but the wrap_indent logic was never updated.

My thought was to remove that redundancy completely, and simply
ask the UI table layer for the correct position.  It turns out
that this needs some new functionality exported from that layer,
but a simply query for the field information you originally
passed to that layer suffices.

The following patch implements this suggestion; it fixes the currently
broken indentation and gets rid of the silly arguments to the
print_breakpoint_location function.

Tested on i386-linux and by manual inspection of line wrapping.

Any comments?

Bye,
Ulrich

ChangeLog:

	* breakpoint.c (wrap_indent_at_field): New function.
	(print_breakpoint_location): Use it instead of WRAP_INDENT argument.
	Allocate ui_stream locally instead of using STB argument.
	(print_one_breakpoint_location): Update call.
	* ui-out.c (ui_out_query_field): New function.
	* ui-out.h (ui_out_query_field): Add prototype.


Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.538
diff -u -p -r1.538 breakpoint.c
--- gdb/breakpoint.c	21 Feb 2011 14:59:34 -0000	1.538
+++ gdb/breakpoint.c	24 Feb 2011 20:16:23 -0000
@@ -4719,12 +4719,40 @@ bpstat_causes_stop (bpstat bs)
 
 \f
 
+/* Compute a string of spaces suitable to indent the next line
+   so it starts at the position corresponding to the table column
+   named COL_NAME in the currently active table of UIOUT.  */
+
+static char *
+wrap_indent_at_field (struct ui_out *uiout, const char *col_name)
+{
+  static char wrap_indent[80];
+  int i, total_width, width, align;
+  char *text;
+
+  total_width = 0;
+  for (i = 1; ui_out_query_field (uiout, i, &width, &align, &text); i++)
+    {
+      if (strcmp (text, col_name) == 0)
+	{
+	  gdb_assert (total_width < sizeof wrap_indent);
+	  memset (wrap_indent, ' ', total_width);
+	  wrap_indent[total_width] = 0;
+
+	  return wrap_indent;
+	}
+
+      total_width += width + 1;
+    }
+
+  return NULL;
+}
+
 /* Print the LOC location out of the list of B->LOC locations.  */
 
-static void print_breakpoint_location (struct breakpoint *b,
-				       struct bp_location *loc,
-				       char *wrap_indent,
-				       struct ui_stream *stb)
+static void
+print_breakpoint_location (struct breakpoint *b,
+			   struct bp_location *loc)
 {
   struct cleanup *old_chain = save_current_program_space ();
 
@@ -4743,8 +4771,9 @@ static void print_breakpoint_location (s
 	  ui_out_text (uiout, "in ");
 	  ui_out_field_string (uiout, "func",
 			       SYMBOL_PRINT_NAME (sym));
-	  ui_out_wrap_hint (uiout, wrap_indent);
-	  ui_out_text (uiout, " at ");
+	  ui_out_text (uiout, " ");
+	  ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
+	  ui_out_text (uiout, "at ");
 	}
       ui_out_field_string (uiout, "file", b->source_file);
       ui_out_text (uiout, ":");
@@ -4762,9 +4791,14 @@ static void print_breakpoint_location (s
     }
   else if (loc)
     {
+      struct ui_stream *stb = ui_out_stream_new (uiout);
+      struct cleanup *stb_chain = make_cleanup_ui_out_stream_delete (stb);
+
       print_address_symbolic (loc->gdbarch, loc->address, stb->stream,
 			      demangle, "");
       ui_out_field_stream (uiout, "at", stb);
+
+      do_cleanups (stb_chain);
     }
   else
     ui_out_field_string (uiout, "pending", b->addr_string);
@@ -4833,9 +4867,6 @@ print_one_breakpoint_location (struct br
 {
   struct command_line *l;
   static char bpenables[] = "nynny";
-  char wrap_indent[80];
-  struct ui_stream *stb = ui_out_stream_new (uiout);
-  struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
   struct cleanup *bkpt_chain;
 
   int header_of_multiple = 0;
@@ -4897,15 +4928,6 @@ print_one_breakpoint_location (struct br
 
   
   /* 5 and 6 */
-  strcpy (wrap_indent, "                           ");
-  if (opts.addressprint)
-    {
-      if (print_address_bits <= 32)
-	strcat (wrap_indent, "           ");
-      else
-	strcat (wrap_indent, "                   ");
-    }
-
   if (b->ops != NULL && b->ops->print_one != NULL)
     {
       /* Although the print_one can possibly print all locations,
@@ -4970,7 +4992,7 @@ print_one_breakpoint_location (struct br
 	  }
 	annotate_field (5);
 	if (!header_of_multiple)
-	  print_breakpoint_location (b, loc, wrap_indent, stb);
+	  print_breakpoint_location (b, loc);
 	if (b->loc)
 	  *last_loc = b->loc;
 	break;
@@ -5126,7 +5148,6 @@ print_one_breakpoint_location (struct br
     }
 	
   do_cleanups (bkpt_chain);
-  do_cleanups (old_chain);
 }
 
 static void
Index: gdb/ui-out.c
===================================================================
RCS file: /cvs/src/src/gdb/ui-out.c,v
retrieving revision 1.51
diff -u -p -r1.51 ui-out.c
--- gdb/ui-out.c	12 Jan 2011 01:23:28 -0000	1.51
+++ gdb/ui-out.c	24 Feb 2011 20:16:23 -0000
@@ -1141,6 +1141,28 @@ ui_out_data (struct ui_out *uiout)
   return uiout->data;
 }
 
+/* Access table field parameters.  */
+int
+ui_out_query_field (struct ui_out *uiout, int colno,
+		    int *width, int *alignment, char **col_name)
+{
+  struct ui_out_hdr *hdr;
+
+  if (!uiout->table.flag)
+    return 0;
+
+  for (hdr = uiout->table.header_first; hdr; hdr = hdr->next)
+    if (hdr->colno == colno)
+      {
+	*width = hdr->width;
+	*alignment = hdr->alignment;
+	*col_name = hdr->col_name;
+	return 1;
+      }
+
+  return 0;
+}
+
 /* Initalize private members at startup.  */
 
 struct ui_out *
Index: gdb/ui-out.h
===================================================================
RCS file: /cvs/src/src/gdb/ui-out.h,v
retrieving revision 1.32
diff -u -p -r1.32 ui-out.h
--- gdb/ui-out.h	12 Jan 2011 01:23:28 -0000	1.32
+++ gdb/ui-out.h	24 Feb 2011 20:16:23 -0000
@@ -156,6 +156,9 @@ extern int ui_out_get_verblvl (struct ui
 
 extern int ui_out_test_flags (struct ui_out *uiout, int mask);
 
+extern int ui_out_query_field (struct ui_out *uiout, int colno,
+			       int *width, int *alignment, char **col_name);
+
 #if 0
 extern void ui_out_result_begin (struct ui_out *uiout, char *class);
 

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints)
  2011-02-24 20:45     ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Ulrich Weigand
@ 2011-02-25 14:46       ` Pedro Alves
  2011-02-28 15:33         ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoin Ulrich Weigand
  2011-02-25 15:33       ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Thiago Jung Bauermann
  1 sibling, 1 reply; 22+ messages in thread
From: Pedro Alves @ 2011-02-25 14:46 UTC (permalink / raw)
  To: gdb-patches; +Cc: Ulrich Weigand, Thiago Jung Bauermann

On Thursday 24 February 2011 20:41:12, Ulrich Weigand wrote:

> Now the thing is, the UI table layer already knows exactly where
> that column starts, so it is kind of pointless to attempt to
> re-compute that offset.  In particular, since the code currently
> gets it completely wrong anyway: at some point, another column of
> variable size was added --see print_type_col_width in breakpoint_1--
> but the wrap_indent logic was never updated.

Whoops.  Guilty, but it goes further back than that.  It looks
like it got broken when we made the "Num" column wider:

7.0:

Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x080912fb in internal_error
                                       at ../../src/gdb/utils.c:1048

6.0:

Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x08122147 in internal_error
                                       at ../../gdb-6.0/gdb/utils.c:807

Shows how fragile that code was.  Makes me wonder about making
that column's width dynamic as well.

> My thought was to remove that redundancy completely, and simply
> ask the UI table layer for the correct position.  It turns out
> that this needs some new functionality exported from that layer,
> but a simply query for the field information you originally
> passed to that layer suffices.
> 
> The following patch implements this suggestion; it fixes the currently
> broken indentation and gets rid of the silly arguments to the
> print_breakpoint_location function.
> 
> Tested on i386-linux and by manual inspection of line wrapping.
> 
> Any comments?

Looks great to me.

I've mentioned this before, but I think it'd really be nice
that the table layout support was reworked to be able to auto
wrap (and size perhaps) columns nicely, à la emacs' org-mode,
vis:

 | Num | Name         | What     | Other column |
 |-----+--------------+----------+--------------|
 |   1 | foo bar      | foo      | another      |
 |     |              | bar what | broken       |
 |     |              |          | sentence     |
 |-----+--------------+----------+--------------|
 |   2 | the other    | what?    | yummy        |

so that all colums would line-break nicely without
messing their rightmost columns.  (without the guide
lines, of course).

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints)
  2011-02-24 20:45     ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Ulrich Weigand
  2011-02-25 14:46       ` Pedro Alves
@ 2011-02-25 15:33       ` Thiago Jung Bauermann
  1 sibling, 0 replies; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-02-25 15:33 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Thu, 2011-02-24 at 21:41 +0100, Ulrich Weigand wrote:
> I'll get back to you with a full review of the latest patch, I just wanted
> to quickly address one specific issue:
> 
> So the whole point of the wrap_indent is to make sure that if the
> description of a breakpoint location is too long to fit into one
> line, it is wrapped at the correct point.  That point happens to
> be the column named "what" in the breakpoint UI table.
> 
> Now the thing is, the UI table layer already knows exactly where
> that column starts, so it is kind of pointless to attempt to
> re-compute that offset.  In particular, since the code currently
> gets it completely wrong anyway: at some point, another column of
> variable size was added --see print_type_col_width in breakpoint_1--
> but the wrap_indent logic was never updated.

Hum, I guess it's high time for me to learn about GDB's printing
mechanisms...

> My thought was to remove that redundancy completely, and simply
> ask the UI table layer for the correct position.  It turns out
> that this needs some new functionality exported from that layer,
> but a simply query for the field information you originally
> passed to that layer suffices.
> 
> The following patch implements this suggestion; it fixes the currently
> broken indentation and gets rid of the silly arguments to the
> print_breakpoint_location function.

Thank you very much for working on this! I really appreciate your help.

> Any comments?

It looks great.

-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoin
  2011-02-25 14:46       ` Pedro Alves
@ 2011-02-28 15:33         ` Ulrich Weigand
  2011-02-28 16:34           ` [commit] Remove unused parameter (Re: [rfc] More intelligent indenting of multi-line table entries) Ulrich Weigand
  0 siblings, 1 reply; 22+ messages in thread
From: Ulrich Weigand @ 2011-02-28 15:33 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Thiago Jung Bauermann

Pedro Alves wrote:
> On Thursday 24 February 2011 20:41:12, Ulrich Weigand wrote:
> > My thought was to remove that redundancy completely, and simply
> > ask the UI table layer for the correct position.  It turns out
> > that this needs some new functionality exported from that layer,
> > but a simply query for the field information you originally
> > passed to that layer suffices.
> >=20
> > The following patch implements this suggestion; it fixes the currently
> > broken indentation and gets rid of the silly arguments to the
> > print_breakpoint_location function.
> >=20
> > Tested on i386-linux and by manual inspection of line wrapping.
> >=20
> > Any comments?
> 
> Looks great to me.

Thanks for the review!  I've checked this in now.
 
> I've mentioned this before, but I think it'd really be nice
> that the table layout support was reworked to be able to auto
> wrap (and size perhaps) columns nicely, =E0 la emacs' org-mode,
> vis:
> 
>  | Num | Name         | What     | Other column |
>  |-----+--------------+----------+--------------|
>  |   1 | foo bar      | foo      | another      |
>  |     |              | bar what | broken       |
>  |     |              |          | sentence     |
>  |-----+--------------+----------+--------------|
>  |   2 | the other    | what?    | yummy        |
> 
> so that all colums would line-break nicely without
> messing their rightmost columns.  (without the guide
> lines, of course).

Yes, ideally the UI table mode should really automatically
lay out the full table.  But right now it seems to be used
interspersed with regular output commands, so getting there
would probably require major changes to the current output
generators ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [commit] Remove unused parameter (Re: [rfc] More intelligent indenting of multi-line table entries)
  2011-02-28 15:33         ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoin Ulrich Weigand
@ 2011-02-28 16:34           ` Ulrich Weigand
  0 siblings, 0 replies; 22+ messages in thread
From: Ulrich Weigand @ 2011-02-28 16:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pedro Alves, Thiago Jung Bauermann

Hello,

I've checked in the following patch as well.  The PRINT_ADDRESS_BITS
parameter is now unused in print_one_breakpoint_location and therefore
print_one_breakpoint, so it should be removed.

Bye,
Ulrich


ChangeLog:

	* breakpoint.c (print_one_breakpoint_location): Remove unused
	argument PRINT_ADDRESS_BITS.  Update callers.
	(print_one_breakpoint): Likewise.

Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.543
diff -u -p -r1.543 breakpoint.c
--- gdb/breakpoint.c	28 Feb 2011 15:21:21 -0000	1.543
+++ gdb/breakpoint.c	28 Feb 2011 16:17:16 -0000
@@ -4708,7 +4708,6 @@ print_one_breakpoint_location (struct br
 			       struct bp_location *loc,
 			       int loc_number,
 			       struct bp_location **last_loc,
-			       int print_address_bits,
 			       int allflag)
 {
   struct command_line *l;
@@ -4999,11 +4998,9 @@ print_one_breakpoint_location (struct br
 static void
 print_one_breakpoint (struct breakpoint *b,
 		      struct bp_location **last_loc, 
-		      int print_address_bits,
 		      int allflag)
 {
-  print_one_breakpoint_location (b, NULL, 0, last_loc,
-				 print_address_bits, allflag);
+  print_one_breakpoint_location (b, NULL, 0, last_loc, allflag);
 
   /* If this breakpoint has custom print function,
      it's already printed.  Otherwise, print individual
@@ -5025,8 +5022,7 @@ print_one_breakpoint (struct breakpoint 
 	  struct bp_location *loc;
 	  int n = 1;
 	  for (loc = b->loc; loc; loc = loc->next, ++n)
-	    print_one_breakpoint_location (b, loc, n, last_loc,
-					   print_address_bits, allflag);
+	    print_one_breakpoint_location (b, loc, n, last_loc, allflag);
 	}
     }
 }
@@ -5070,9 +5066,7 @@ do_captured_breakpoint_query (struct ui_
     {
       if (args->bnum == b->number)
 	{
-	  int print_address_bits = breakpoint_address_bits (b);
-
-	  print_one_breakpoint (b, &dummy_loc, print_address_bits, 0);
+	  print_one_breakpoint (b, &dummy_loc, 0);
 	  return GDB_RC_OK;
 	}
     }
@@ -5243,7 +5237,7 @@ breakpoint_1 (char *args, int allflag, 
       /* We only print out user settable breakpoints unless the
 	 allflag is set.  */
       if (allflag || user_breakpoint_p (b))
-	print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
+	print_one_breakpoint (b, &last_loc, allflag);
     }
 
   do_cleanups (bkpttbl_chain);

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-02-23 20:50   ` Thiago Jung Bauermann
  2011-02-24 20:45     ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Ulrich Weigand
@ 2011-02-28 17:08     ` Ulrich Weigand
  2011-03-12  2:03       ` Thiago Jung Bauermann
  1 sibling, 1 reply; 22+ messages in thread
From: Ulrich Weigand @ 2011-02-28 17:08 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> The callers of breakpoint_address_match that I didn't change are:
> 
> breakpoint_restore_shadows (only software breakpoints have shadow
> contents), bpstat_check_location (it calls ops->breakpoint_hit if
> available, which will do the right thing for the bp_location at hand),
> single_step_breakpoint_inserted_here_p (it calls
> breakpoint_address_match for something which isn't a bp_location, also a
> comment there says it checks only software breakpoints). 

This seems reasonable to me.

> > > @@ -3306,11 +3318,6 @@ print_it_typical (bpstat bs)
> > >    int bp_temp = 0;
> > >    enum print_stop_action result;
> > >  
> > > -  /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
> > > -     which has since been deleted.  */
> > > -  if (bs->breakpoint_at == NULL)
> > > -    return PRINT_UNKNOWN;
> > > -
> > >    gdb_assert (bs->bp_location_at != NULL);
> > >  
> > >    bl = bs->bp_location_at;
> > > @@ -3516,11 +3523,15 @@ print_bp_stop_message (bpstat bs)
> > >        {
> > >  	struct breakpoint *b = bs->breakpoint_at;
> > >  
> > > +	/* bs->breakpoint_at can be NULL if it was a momentary breakpoint
> > > +	   which has since been deleted.  */
> > > +	if (b == NULL)
> > > +	  return PRINT_UNKNOWN;
> > > +
> > >  	/* Normal case.  Call the breakpoint's print_it method, or
> > >  	   print_it_typical.  */
> > > -	/* FIXME: how breakpoint can ever be NULL here?  */
> > 
> > This seems to be an unrelated change, isn't it?
> 
> I consider it to be related. In this patch series I'm revamping the
> breakpoint_ops methods to make them more suitable for implementing
> breakpoints and watchpoints. print_it_typical is part of that, so an
> improvement in a function which calls the print_it method and
> print_it_typcal seemed to have a place in this patch.
> 
> I don't mind submitting this in a separate patch if you want. 

Yes, please do so.  I think this could go in right away.

> > This adds the SAY_WHERE parameter so that the caller will go ahead to
> > add location information.  However, for a range breakpoint, this will
> > just be the start of the range, which may or may not be particularly
> > useful ...   Shouldn't we either:
> > - output the full range (start and end),  or
> > - output nothing ... we'll see the actual location where we stopped anyway
> > 
> > (Either way, the API change to add SAY_WHERE is no longer needed.)
> 
> I think it's useful. You have a point in that it makes more sense to
> print the end of the range as well. I'd have to extend struct breakpoint
> to save the source file and line number of the end of the range if I
> were to print them. I'm not sure it's worth it, so I changed
> print_mention_ranged_breakpoint to print only the start and end address
> of the range. And dropped the say_where argument. What do you think? 

Don't you have to know the end of the range anyway, in order to be
able to re-set the breakpoint?

> +static enum print_stop_action
> +print_it_ranged_breakpoint (struct breakpoint *b,
> +			    const struct value *old_val)

Hmm ... this is not against current mainline, but assumes some of
the other patches is applied as well, right?

> +{
> +  struct bp_location *bl = b->loc;
> +  struct ui_stream *stb;
> +  struct cleanup *old_chain;
> +
> +  gdb_assert (b->type == bp_hardware_breakpoint);
> +
> +  /* Ranged breakpoints have only one location.  */
> +  gdb_assert (bl && bl->next == NULL);
> +
> +  stb = ui_out_stream_new (uiout);
> +  old_chain = make_cleanup_ui_out_stream_delete (stb);

You never use this stream, what's the point of allocating it?

> +  annotate_breakpoint (b->number);
> +  if (b->disposition == disp_del)
> +    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
> +  else
> +    ui_out_text (uiout, "\nHardware assisted ranged breakpoint ");

Either both or none of these should be using "hardware assisted".
I'd probably argue for "none": for regular breakpoint, this
distinction is not made here either ...


> +static void
> +print_one_ranged_breakpoint (struct breakpoint *b,
> +			     struct bp_location **last_loc,
> +			     char *wrap_indent)
> +{
> +  struct bp_location *bl = b->loc;
> +  struct value_print_options opts;
> +  struct ui_stream *stb = ui_out_stream_new (uiout);
> +  struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);

Again the unused stream ...

> +  /* Ranged breakpoints have only one location.  */
> +  gdb_assert (bl && bl->next == NULL);
> +
> +  get_user_print_options (&opts);
> +
> +  if (opts.addressprint)
> +    ui_out_field_skip (uiout, "addr");
> +  annotate_field (5);
> +  if (bl->enabled)
> +    print_breakpoint_location (b, bl, wrap_indent, stb);

I think you should not check bl->enabled here like that.  This is
done for regular breakpoints only because enabled breakpoints with
a single disabled location are handled by special code in print_one_breakpoint
which is not active for breakpoints with custom functions.

> +static void
> +print_one_detail_ranged_breakpoint (const struct breakpoint *b,
> +				    struct ui_out *uiout)
> +{
> +  struct bp_location *bl = b->loc;
> +
> +  gdb_assert (bl);
> +
> +  ui_out_text (uiout, "\taddress range: ");
> +  ui_out_field_range_core_addr (uiout, "addr", bl->gdbarch,
> +				bl->address, bl->length);

Do we really need to make a new ui_out_ function for this; this
seems a bit of a special case for that.  Why don't you just generate
the output here?   (Note that here you might want to use a temporary
stream like the one you had in the above functions but never used
there ...)

> +static void
> +break_range_command (char *arg, int from_tty)
> +{
> +  char *orig_arg;
> +  char **addr_string_start;
> +  int bp_count, can_use_bp, ret;
> +  CORE_ADDR start_addr, start, end;
> +  int length;
> +  struct breakpoint *b;
> +  struct symtabs_and_lines sals_start, sals_end;
> +  struct gdbarch *gdbarch = get_current_arch ();
> +  struct gdb_exception e;
> +  struct cleanup *cleanup_start, *cleanup_end, *cleanup_orig_arg;
> +
> +  /* We don't support software ranged breakpoints.  */
> +  if (target_ranged_break_num_registers () < 0)
> +    error (_("This target does not support hardware ranged breakpoints."));
> +
> +  bp_count = hw_breakpoint_used_count ();
> +  bp_count += target_ranged_break_num_registers ();
> +  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
> +						   bp_count, 0);
> +  if (can_use_bp < 0)
> +    error (_("Hardware breakpoints used exceeds limit."));
> +
> +  if (arg == NULL || arg[0] == '\0')
> +    error(_("No address range specified."));
> +
> +  /* Save the original argument string for later use by
> +     print_recreate_ranged_hw_breakpoint.  */
> +  orig_arg = xstrdup (arg);
> +  /* We'll only dispose of it if this function is aborted.  */
> +  cleanup_orig_arg = make_cleanup (xfree, orig_arg);
> +
> +  sals_start.sals = NULL;
> +  sals_start.nelts = 0;
> +  addr_string_start = NULL;
> +
> +  while (*arg == ' ' || *arg == '\t')
> +    arg++;
> +
> +  parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
> +
> +  cleanup_start = make_cleanup (xfree, sals_start.sals);
> +  make_cleanup (xfree, addr_string_start);
> +  make_cleanup (xfree, addr_string_start[0]);
> +
> +  if (arg[0] != ',')
> +    error (_("Too few arguments."));
> +  else if (sals_start.nelts == 0)
> +    error (_("Could not find location of the beginning of the range."));
> +  else if (sals_start.nelts != 1)
> +    error (_("Cannot create a ranged breakpoint with multiple locations."));
> +
> +  breakpoint_sals_to_pc (&sals_start);
> +  start_addr = sals_start.sals[0].pc;
> +
> +  arg++;	/* Skip the comma.  */
> +  while (*arg == ' ' || *arg == '\t')
> +    arg++;
> +
> +  /* Parse the end location.  */
> +
> +  sals_end.sals = NULL;
> +  sals_end.nelts = 0;
> +
> +  sals_end = decode_line_1 (&arg, 1, sals_start.sals[0].symtab,
> +			    sals_start.sals[0].line, 0, 0);

It seems oddly asymmetrical to use parse_breakpoint_sals above but
decode_line_1 here.  Shouldn't start and end of the range use the
same symtab defaulting rules and other extra treatment done by
parse_breakpoint_sals?

> @@ -598,6 +598,7 @@ update_current_target (void)
>        INHERIT (to_can_use_hw_breakpoint, t);
>        INHERIT (to_insert_hw_breakpoint, t);
>        INHERIT (to_remove_hw_breakpoint, t);
> +      /* Do not inherit to_ranged_break_num_registers.  */
>        INHERIT (to_insert_watchpoint, t);
>        INHERIT (to_remove_watchpoint, t);
>        /* Do not inherit to_insert_mask_watchpoint.  */

Again the question why the inheritance logic for this function
should be different than for all the other breakpoint-related
functions ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-02-28 17:08     ` [RFA] Implement support for PowerPC BookE ranged breakpoints Ulrich Weigand
@ 2011-03-12  2:03       ` Thiago Jung Bauermann
  2011-03-12 16:44         ` Thiago Jung Bauermann
  2011-03-14 21:02         ` Ulrich Weigand
  0 siblings, 2 replies; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-03-12  2:03 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Mon, 2011-02-28 at 17:52 +0100, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> > > This adds the SAY_WHERE parameter so that the caller will go ahead to
> > > add location information.  However, for a range breakpoint, this will
> > > just be the start of the range, which may or may not be particularly
> > > useful ...   Shouldn't we either:
> > > - output the full range (start and end),  or
> > > - output nothing ... we'll see the actual location where we stopped anyway
> > > 
> > > (Either way, the API change to add SAY_WHERE is no longer needed.)
> > 
> > I think it's useful. You have a point in that it makes more sense to
> > print the end of the range as well. I'd have to extend struct breakpoint
> > to save the source file and line number of the end of the range if I
> > were to print them. I'm not sure it's worth it, so I changed
> > print_mention_ranged_breakpoint to print only the start and end address
> > of the range. And dropped the say_where argument. What do you think? 
> 
> Don't you have to know the end of the range anyway, in order to be
> able to re-set the breakpoint?

I was thinking of the struct breakpoint's source_file and line_number,
which are used mostly for printing (clear_command uses it for finding
breakpoints). For print_mention_ranged_breakpoint I'd need
source_file_range_end and line_number_range_end, but decided against it.

But now that you mention breakpoint re-setting, I just realised that I
need to add addr_string_range_end and make breakpoint_re_set_one use it.
As the patch currently stands, ranged breakpoints will be dropped when
loading new binaries... I'm currently working on this but decided to
send this patch as it is since it addresses all the other points you
raised.

> > +static enum print_stop_action
> > +print_it_ranged_breakpoint (struct breakpoint *b,
> > +			    const struct value *old_val)
> 
> Hmm ... this is not against current mainline, but assumes some of
> the other patches is applied as well, right?

Yes, it applied on top of the masked watchpoints patch. Since this one
seems to be closer to being accepted than the masked watchpoints one, I
reordered the series and now this patch applies directly to mainline.
The changes were minimal (just had to add the print_one_detail
breakpoint_ops method).

> > +{
> > +  struct bp_location *bl = b->loc;
> > +  struct ui_stream *stb;
> > +  struct cleanup *old_chain;
> > +
> > +  gdb_assert (b->type == bp_hardware_breakpoint);
> > +
> > +  /* Ranged breakpoints have only one location.  */
> > +  gdb_assert (bl && bl->next == NULL);
> > +
> > +  stb = ui_out_stream_new (uiout);
> > +  old_chain = make_cleanup_ui_out_stream_delete (stb);
> 
> You never use this stream, what's the point of allocating it?

Ouch, leftover from some intermediate version of the code. :-/ Removed.

> > +  annotate_breakpoint (b->number);
> > +  if (b->disposition == disp_del)
> > +    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
> > +  else
> > +    ui_out_text (uiout, "\nHardware assisted ranged breakpoint ");
> 
> Either both or none of these should be using "hardware assisted".
> I'd probably argue for "none": for regular breakpoint, this
> distinction is not made here either ...

Good point. Dropped "hardware assisted".

> > +static void
> > +print_one_ranged_breakpoint (struct breakpoint *b,
> > +			     struct bp_location **last_loc,
> > +			     char *wrap_indent)
> > +{
> > +  struct bp_location *bl = b->loc;
> > +  struct value_print_options opts;
> > +  struct ui_stream *stb = ui_out_stream_new (uiout);
> > +  struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
> 
> Again the unused stream ...

Ugh.

> > +  /* Ranged breakpoints have only one location.  */
> > +  gdb_assert (bl && bl->next == NULL);
> > +
> > +  get_user_print_options (&opts);
> > +
> > +  if (opts.addressprint)
> > +    ui_out_field_skip (uiout, "addr");
> > +  annotate_field (5);
> > +  if (bl->enabled)
> > +    print_breakpoint_location (b, bl, wrap_indent, stb);
> 
> I think you should not check bl->enabled here like that.  This is
> done for regular breakpoints only because enabled breakpoints with
> a single disabled location are handled by special code in print_one_breakpoint
> which is not active for breakpoints with custom functions.

Good point. I had to stare at the code for a while to understand (again)
what was going on with print_one_breakpoint and
print_breakpoint_location, it's not very easy to follow (and I thought I
got it right the first time!). Now I just call print_breakpoint_location
directly.

> > +static void
> > +print_one_detail_ranged_breakpoint (const struct breakpoint *b,
> > +				    struct ui_out *uiout)
> > +{
> > +  struct bp_location *bl = b->loc;
> > +
> > +  gdb_assert (bl);
> > +
> > +  ui_out_text (uiout, "\taddress range: ");
> > +  ui_out_field_range_core_addr (uiout, "addr", bl->gdbarch,
> > +				bl->address, bl->length);
> 
> Do we really need to make a new ui_out_ function for this; this
> seems a bit of a special case for that.  Why don't you just generate
> the output here?   (Note that here you might want to use a temporary
> stream like the one you had in the above functions but never used
> there ...)

I think I was using that function somewhere else in a previous
incarnation of this patch series, so it stayed. I didn't think it was a
problem since it is analogous to other functions in ui-out.c. 

> > +static void
> > +break_range_command (char *arg, int from_tty)
> > +{
> > +  char *orig_arg;
> > +  char **addr_string_start;
> > +  int bp_count, can_use_bp, ret;
> > +  CORE_ADDR start_addr, start, end;
> > +  int length;
> > +  struct breakpoint *b;
> > +  struct symtabs_and_lines sals_start, sals_end;
> > +  struct gdbarch *gdbarch = get_current_arch ();
> > +  struct gdb_exception e;
> > +  struct cleanup *cleanup_start, *cleanup_end, *cleanup_orig_arg;
> > +
> > +  /* We don't support software ranged breakpoints.  */
> > +  if (target_ranged_break_num_registers () < 0)
> > +    error (_("This target does not support hardware ranged breakpoints."));
> > +
> > +  bp_count = hw_breakpoint_used_count ();
> > +  bp_count += target_ranged_break_num_registers ();
> > +  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
> > +						   bp_count, 0);
> > +  if (can_use_bp < 0)
> > +    error (_("Hardware breakpoints used exceeds limit."));
> > +
> > +  if (arg == NULL || arg[0] == '\0')
> > +    error(_("No address range specified."));
> > +
> > +  /* Save the original argument string for later use by
> > +     print_recreate_ranged_hw_breakpoint.  */
> > +  orig_arg = xstrdup (arg);
> > +  /* We'll only dispose of it if this function is aborted.  */
> > +  cleanup_orig_arg = make_cleanup (xfree, orig_arg);
> > +
> > +  sals_start.sals = NULL;
> > +  sals_start.nelts = 0;
> > +  addr_string_start = NULL;
> > +
> > +  while (*arg == ' ' || *arg == '\t')
> > +    arg++;
> > +
> > +  parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
> > +
> > +  cleanup_start = make_cleanup (xfree, sals_start.sals);
> > +  make_cleanup (xfree, addr_string_start);
> > +  make_cleanup (xfree, addr_string_start[0]);
> > +
> > +  if (arg[0] != ',')
> > +    error (_("Too few arguments."));
> > +  else if (sals_start.nelts == 0)
> > +    error (_("Could not find location of the beginning of the range."));
> > +  else if (sals_start.nelts != 1)
> > +    error (_("Cannot create a ranged breakpoint with multiple locations."));
> > +
> > +  breakpoint_sals_to_pc (&sals_start);
> > +  start_addr = sals_start.sals[0].pc;
> > +
> > +  arg++;	/* Skip the comma.  */
> > +  while (*arg == ' ' || *arg == '\t')
> > +    arg++;
> > +
> > +  /* Parse the end location.  */
> > +
> > +  sals_end.sals = NULL;
> > +  sals_end.nelts = 0;
> > +
> > +  sals_end = decode_line_1 (&arg, 1, sals_start.sals[0].symtab,
> > +			    sals_start.sals[0].line, 0, 0);
> 
> It seems oddly asymmetrical to use parse_breakpoint_sals above but
> decode_line_1 here.  Shouldn't start and end of the range use the
> same symtab defaulting rules and other extra treatment done by
> parse_breakpoint_sals?

No, the end location should default to the same file and line number as
the start location. This makes it possible to have ranges like:

(gdb) break-range foo.c:27, +14

Had I used parse_breakpoint_sals, GDB would interpret "+14" as "14 lines
from the current file and line number", and not "14 lines from the start
location". As for the extra treatment, I had a look at them before and
didn't think they applied in the context of resolving the end location.

Though perhaps now that I'll need to have a b->addr_string_range_end,
the code ensuring there are addr_strings may be useful. I don't know
yet.

> > @@ -598,6 +598,7 @@ update_current_target (void)
> >        INHERIT (to_can_use_hw_breakpoint, t);
> >        INHERIT (to_insert_hw_breakpoint, t);
> >        INHERIT (to_remove_hw_breakpoint, t);
> > +      /* Do not inherit to_ranged_break_num_registers.  */
> >        INHERIT (to_insert_watchpoint, t);
> >        INHERIT (to_remove_watchpoint, t);
> >        /* Do not inherit to_insert_mask_watchpoint.  */
> 
> Again the question why the inheritance logic for this function
> should be different than for all the other breakpoint-related
> functions ...

This was pointed out to me by Jan when reviewing another patch [1]:

> > --- a/gdb/target.c
> > +++ b/gdb/target.c
> > @@ -601,11 +601,16 @@ update_current_target (void)
> >        INHERIT (to_files_info, t);
> >        INHERIT (to_insert_breakpoint, t);
> >        INHERIT (to_remove_breakpoint, t);
> > +      INHERIT (to_can_use_special_hw_point, t);
> 
> There are now two target interface styles in use.  This inheriting one and the
> runtime-inheriting one (see target_pid_to_str and others).  I was told the
> target_pid_to_str style is now preferred and it makes sense to me.  Please
> convert the new target vector methods to the new style.

So I just followed his advice and used the new method instead of the
deprecated one which is used by the other breakpoint-related functions.

[1] http://sourceware.org/ml/gdb-patches/2010-11/msg00193.html
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-03-11  Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

	Implement support for PowerPC BookE ranged breakpoints.

gdb/
	* NEWS: Mention support for ranged breakpoints on embedded
	PowerPC.
	* breakpoint.h (struct bp_target_info) <length>: New member
	variable.
	(struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
	instead of struct breakpoint as argument, and also add ASPACE
	and BP_ADDR arguments.  Update all callers.
	(struct breakpoint_ops) <print_one_detail>: New method.
	* breakpoint.c (breakpoint_location_address_match): Add function
	prototype.
	(insert_bp_location): Set bl->target_info.length.
	(breakpoint_here_p): Call breakpoint_location_address_match.
	(moribund_breakpoint_here_p): Likewise.
	(regular_breakpoint_inserted_here_p): Likewise.
	(breakpoint_thread_match): Likewise.
	(bpstat_stop_status): Likewise.
	(bpstat_check_location): Move call to
	breakpoint_ops.breakpoint_hit to the top.
	(print_one_breakpoint_location): Call
	breakpoint_ops.print_one_detail if available.
	(breakpoint_address_match_range): New function.
	(breakpoint_location_address_match): New function.
	(breakpoint_locations_match): Compare the length field of the
	locations too.
	(hw_breakpoint_used_count): Count resources used by all locations
	in a breakpoint, and use breakpoint_ops.resources_needed if
	available.
	(breakpoint_hit_ranged_breakpoint): New function.
	(resources_needed_ranged_breakpoint): Likewise.
	(print_it_ranged_breakpoint): Likewise.
	(print_one_ranged_breakpoint): Likewise.
	(print_one_detail_ranged_breakpoint): Likewise.
	(print_mention_ranged_breakpoint): Likewise.
	(print_recreate_ranged_breakpoint): Likewise.
	(ranged_breakpoint_ops): New structure.
	(break_range_command): New function.
	(update_breakpoint_locations): Call breakpoint_locations_match
	instead of breakpoint_address_match.
	(_initialize_breakpoint): Register break-range command.
	* ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
	function.
	(ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
	(ppc_linux_remove_hw_breakpoint): Likewise.
	(_initialize_ppc_linux_nat): Initialize
	to_ranged_break_num_registers.
	* target.c (update_current_target): Add comment about
	to_ranged_break_num_registers.
	(target_ranged_break_num_registers): New function.
	* target.h (struct target_ops) <to_ranged_break_num_registers>:
	New method.
	(target_ranged_break_num_registers): Add function prototype.

gdb/doc/
	* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index fb36383..ece514e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -147,6 +147,12 @@
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
+  which stop execution of the inferior whenever it executes an instruction
+  at any address within the specified range.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index ed51ab0..93f6da9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10924,6 +10924,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10963,6 +10964,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* resources_needed */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -11000,6 +11002,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* resources_needed */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 5bcab87..edcfe13 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -129,6 +129,10 @@ static int breakpoint_address_match (struct address_space *aspace1,
 static int watchpoint_locations_match (struct bp_location *loc1,
 				       struct bp_location *loc2);
 
+static int breakpoint_location_address_match (struct bp_location *bl,
+					      struct address_space *aspace,
+					      CORE_ADDR addr);
+
 static void breakpoints_info (char *, int);
 
 static void watchpoints_info (char *, int);
@@ -1512,6 +1516,7 @@ insert_bp_location (struct bp_location *bl,
   memset (&bl->target_info, 0, sizeof (bl->target_info));
   bl->target_info.placed_address = bl->address;
   bl->target_info.placed_address_space = bl->pspace->aspace;
+  bl->target_info.length = bl->length;
 
   if (bl->loc_type == bp_loc_software_breakpoint
       || bl->loc_type == bp_loc_hardware_breakpoint)
@@ -2774,11 +2779,10 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
 	  && bl->loc_type != bp_loc_hardware_breakpoint)
 	continue;
 
-      /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL.  */
+      /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL.  */
       if ((breakpoint_enabled (bl->owner)
 	   || bl->owner->enable_state == bp_permanent)
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2803,8 +2807,7 @@ moribund_breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
   int ix;
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
-    if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				  aspace,  pc))
+    if (breakpoint_location_address_match (loc, aspace, pc))
       return 1;
 
   return 0;
@@ -2828,8 +2831,7 @@ regular_breakpoint_inserted_here_p (struct address_space *aspace,
 	continue;
 
       if (bl->inserted
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2946,8 +2948,7 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
 	  && bl->owner->enable_state != bp_permanent)
 	continue;
 
-      if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
-				     aspace, pc))
+      if (!breakpoint_location_address_match (bl, aspace, pc))
 	continue;
 
       if (bl->owner->thread != -1)
@@ -3837,6 +3838,9 @@ bpstat_check_location (const struct bp_location *bl,
   /* BL is from existing struct breakpoint.  */
   gdb_assert (b != NULL);
 
+  if (b->ops && b->ops->breakpoint_hit)
+    return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+
   /* By definition, the inferior does not report stops at
      tracepoints.  */
   if (is_tracepoint (b))
@@ -3865,7 +3869,7 @@ bpstat_check_location (const struct bp_location *bl,
   if (is_hardware_watchpoint (b)
       && b->watchpoint_triggered == watch_triggered_no)
     return 0;
-  
+
   if (b->type == bp_hardware_breakpoint)
     {
       if (bl->address != bp_addr)
@@ -3876,13 +3880,6 @@ bpstat_check_location (const struct bp_location *bl,
 	return 0;
     }
 
-  if (b->type == bp_catchpoint)
-    {
-      gdb_assert (b->ops != NULL && b->ops->breakpoint_hit != NULL);
-      if (!b->ops->breakpoint_hit (b))
-        return 0;
-    }
-     
   return 1;
 }
 
@@ -4239,8 +4236,7 @@ bpstat_stop_status (struct address_space *aspace,
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
     {
-      if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				    aspace, bp_addr))
+      if (breakpoint_location_address_match (loc, aspace, bp_addr))
 	{
 	  bs = bpstat_alloc (loc, &bs_link);
 	  /* For hits of moribund locations, we should just proceed.  */
@@ -4889,9 +4885,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5473,6 +5472,39 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
 	  && addr1 == addr2);
 }
 
+/* Returns true if {ASPACE2,ADDR2} falls within the range determined by
+   {ASPACE1,ADDR1,LEN1}.  In most targets, this can only be true if ASPACE1
+   matches ASPACE2.  On targets that have global breakpoints, the address
+   space doesn't really matter.  */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+				int len1, struct address_space *aspace2,
+				CORE_ADDR addr2)
+{
+  return ((gdbarch_has_global_breakpoints (target_gdbarch)
+	   || aspace1 == aspace2)
+	  && addr2 >= addr1 && addr2 < addr1 + len1);
+}
+
+/* Returns true if {ASPACE,ADDR} matches the breakpoint BL.  BL may be
+   a ranged breakpoint.  In most targets, a match happens only if ASPACE
+   matches the breakpoint's address space.  On targets that have global
+   breakpoints, the address space doesn't really matter.  */
+
+static int
+breakpoint_location_address_match (struct bp_location *bl,
+				   struct address_space *aspace,
+				   CORE_ADDR addr)
+{
+  return (breakpoint_address_match (bl->pspace->aspace, bl->address,
+				    aspace, addr)
+	  || (bl->length
+	      && breakpoint_address_match_range (bl->pspace->aspace,
+						 bl->address, bl->length,
+						 aspace, addr)));
+}
+
 /* Assuming LOC1 and LOC2's types' have meaningful target addresses
    (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
    represent the same location.  */
@@ -5495,8 +5527,10 @@ breakpoint_locations_match (struct bp_location *loc1,
   else if (hw_point1)
     return watchpoint_locations_match (loc1, loc2);
   else
-    return breakpoint_address_match (loc1->pspace->aspace, loc1->address,
-				     loc2->pspace->aspace, loc2->address);
+    /* We compare bp_location.length in order to cover ranged breakpoints.  */
+    return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
+				     loc2->pspace->aspace, loc2->address)
+	    && loc1->length == loc2->length);
 }
 
 static void
@@ -6105,9 +6139,10 @@ remove_catch_fork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_fork (struct breakpoint *b)
+breakpoint_hit_catch_fork (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_forked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for fork
@@ -6176,6 +6211,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -6202,9 +6238,10 @@ remove_catch_vfork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_vfork (struct breakpoint *b)
+breakpoint_hit_catch_vfork (const struct bp_location *bl,
+			    struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_vforked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for vfork
@@ -6272,6 +6309,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6361,12 +6399,14 @@ remove_catch_syscall (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_syscall (struct breakpoint *b)
+breakpoint_hit_catch_syscall (const struct bp_location *bl,
+			      struct address_space *aspace, CORE_ADDR bp_addr)
 {
   /* We must check if we are catching specific syscalls in this
      breakpoint.  If we are, then we must guarantee that the called
      syscall is the same syscall we are catching.  */
   int syscall_number = 0;
+  const struct breakpoint *b = bl->owner;
 
   if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
     return 0;
@@ -6435,7 +6475,7 @@ print_it_catch_syscall (struct breakpoint *b)
 
 static void
 print_one_catch_syscall (struct breakpoint *b,
-                         struct bp_location **last_loc)
+			 struct bp_location **last_loc)
 {
   struct value_print_options opts;
 
@@ -6556,6 +6596,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6651,9 +6692,10 @@ remove_catch_exec (struct bp_location *bl)
 }
 
 static int
-breakpoint_hit_catch_exec (struct breakpoint *b)
+breakpoint_hit_catch_exec (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_execd (inferior_ptid, &b->exec_pathname);
+  return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
 }
 
 static enum print_stop_action
@@ -6710,6 +6752,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6733,13 +6776,22 @@ create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
 static int
 hw_breakpoint_used_count (void)
 {
-  struct breakpoint *b;
   int i = 0;
+  struct breakpoint *b;
+  struct bp_location *bl;
 
   ALL_BREAKPOINTS (b)
   {
     if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
-      i++;
+      for (bl = b->loc; bl; bl = bl->next)
+	{
+	  /* Special types of hardware breakpoints may use more than
+	     one register.  */
+	  if (b->ops && b->ops->resources_needed)
+	    i += b->ops->resources_needed (bl);
+	  else
+	    i++;
+	}
   }
 
   return i;
@@ -8199,6 +8251,289 @@ stopat_command (char *arg, int from_tty)
     break_command_1 (arg, 0, from_tty);
 }
 
+/* Implement the "breakpoint_hit" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+				  struct address_space *aspace,
+				  CORE_ADDR bp_addr)
+{
+  return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+					 bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+  return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  annotate_breakpoint (b->number);
+  if (b->disposition == disp_del)
+    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+  else
+    ui_out_text (uiout, "\nRanged breakpoint ");
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+    }
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
+
+  return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+			     struct bp_location **last_loc)
+{
+  struct bp_location *bl = b->loc;
+  struct value_print_options opts;
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  get_user_print_options (&opts);
+
+  if (opts.addressprint)
+    /* We don't print the address range here, it will be printed later
+       by print_one_detail_ranged_breakpoint.  */
+    ui_out_field_skip (uiout, "addr");
+  annotate_field (5);
+  print_breakpoint_location (b, bl);
+  *last_loc = bl;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  int addr_bit, hex_width;
+  CORE_ADDR address_start, address_end;
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (bl);
+
+  addr_bit = gdbarch_addr_bit (bl->gdbarch);
+  hex_width = addr_bit / 4;
+  address_start = bl->address;
+  address_end = address_start + bl->length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    {
+      address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+      address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    }
+
+  ui_out_text (uiout, "\taddress range: ");
+  ui_out_field_fmt (uiout, "addr", "[%s, %s]",
+		    hex_string_custom (address_start, hex_width),
+		    hex_string_custom (address_end, hex_width));
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (bl);
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  if (ui_out_is_mi_like_p (uiout))
+    return;
+
+  printf_filtered (_("Hardware assisted ranged breakpoint %d from %s to %s."),
+		   b->number, paddress (bl->gdbarch, bl->address),
+		   paddress (bl->gdbarch, bl->address + bl->length - 1));
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  fprintf_unfiltered (fp, "break-range %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints.  */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+  NULL, /* insert */
+  NULL, /* remove */
+  breakpoint_hit_ranged_breakpoint,
+  resources_needed_ranged_breakpoint,
+  print_it_ranged_breakpoint,
+  print_one_ranged_breakpoint,
+  print_one_detail_ranged_breakpoint,
+  print_mention_ranged_breakpoint,
+  print_recreate_ranged_breakpoint
+};
+
+/* Implement the "break-range" CLI command.  */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+  char *orig_arg;
+  char **addr_string_start;
+  int bp_count, can_use_bp, ret;
+  CORE_ADDR start_addr, start, end;
+  int length;
+  struct breakpoint *b;
+  struct symtabs_and_lines sals_start, sals_end;
+  struct gdbarch *gdbarch = get_current_arch ();
+  struct gdb_exception e;
+  struct cleanup *cleanup_start, *cleanup_end, *cleanup_orig_arg;
+
+  /* We don't support software ranged breakpoints.  */
+  if (target_ranged_break_num_registers () < 0)
+    error (_("This target does not support hardware ranged breakpoints."));
+
+  bp_count = hw_breakpoint_used_count ();
+  bp_count += target_ranged_break_num_registers ();
+  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+						   bp_count, 0);
+  if (can_use_bp < 0)
+    error (_("Hardware breakpoints used exceeds limit."));
+
+  if (arg == NULL || arg[0] == '\0')
+    error(_("No address range specified."));
+
+  /* Save the original argument string for later use by
+     print_recreate_ranged_hw_breakpoint.  */
+  orig_arg = xstrdup (arg);
+  /* We'll only dispose of it if this function is aborted.  */
+  cleanup_orig_arg = make_cleanup (xfree, orig_arg);
+
+  sals_start.sals = NULL;
+  sals_start.nelts = 0;
+  addr_string_start = NULL;
+
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
+
+  cleanup_start = make_cleanup (xfree, sals_start.sals);
+  make_cleanup (xfree, addr_string_start);
+  make_cleanup (xfree, addr_string_start[0]);
+
+  if (arg[0] != ',')
+    error (_("Too few arguments."));
+  else if (sals_start.nelts == 0)
+    error (_("Could not find location of the beginning of the range."));
+  else if (sals_start.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  breakpoint_sals_to_pc (&sals_start);
+  start_addr = sals_start.sals[0].pc;
+
+  arg++;	/* Skip the comma.  */
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  /* Parse the end location.  */
+
+  sals_end.sals = NULL;
+  sals_end.nelts = 0;
+
+  sals_end = decode_line_1 (&arg, 1, sals_start.sals[0].symtab,
+			    sals_start.sals[0].line, NULL, NULL);
+
+  cleanup_end = make_cleanup (xfree, sals_end.sals);
+
+  if (sals_end.nelts == 0)
+    error (_("Could not find location of the end of the range."));
+  else if (sals_end.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  breakpoint_sals_to_pc (&sals_end);
+
+  /* If the user provided a PC value, use it.  Otherwise, find the
+     address of the end of the given location.  */
+  if (sals_end.sals[0].explicit_pc)
+    end = sals_end.sals[0].pc;
+  else
+    {
+      ret = find_line_pc_range (sals_end.sals[0], &start, &end);
+      if (!ret)
+	error (_("Could not find location of the end of the range."));
+
+      /* find_line_pc_range returns the start of the next line.  */
+      end--;
+    }
+
+  if (start_addr > end)
+    error (_("Invalid address range, end preceeds start."));
+
+  length = end - start_addr + 1;
+  if (length < 0)
+    /* Length overflowed.  */
+    error (_("Address range too large."));
+  else if (length == 1)
+    {
+      /* This range is simple enough to be handled by
+	 the `hbreak' command.  */
+      hbreak_command (addr_string_start[0], 1);
+
+      do_cleanups (cleanup_orig_arg);
+
+      return;
+    }
+
+  do_cleanups (cleanup_end);
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sals_start.sals[0], bp_hardware_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = NULL;
+  b->exp_string = orig_arg;
+  b->val = NULL;
+  b->val_valid = 0;
+  b->ops = &ranged_breakpoint_ops;
+  b->loc->length = length;
+
+  do_cleanups (cleanup_start);
+  discard_cleanups (cleanup_orig_arg);
+
+  mention (b);
+  update_global_location_list (1);
+}
+
 /*  Return non-zero if EXP is verified as constant.  Returned zero
     means EXP is variable.  Also the constant detection may fail for
     some constant expressions and in such case still falsely return
@@ -8351,6 +8686,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   resources_needed_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
@@ -9130,6 +9466,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* resources_needed */
   print_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -10441,8 +10778,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	    if (have_ambiguous_names)
 	      {
 		for (; l; l = l->next)
-		  if (breakpoint_address_match (e->pspace->aspace, e->address,
-						l->pspace->aspace, l->address))
+		  if (breakpoint_locations_match (e, l))
 		    {
 		      l->enabled = 0;
 		      break;
@@ -12564,7 +12900,23 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
 			   &show_always_inserted_mode,
 			   &breakpoint_set_cmdlist,
 			   &breakpoint_show_cmdlist);
-  
+
+  add_com ("break-range", class_breakpoint, break_range_command, _("\
+Set a breakpoint for an address range.\n\
+break-range START-LOCATION, END-LOCATION\n\
+where START-LOCATION and END-LOCATION can be one of the following:\n\
+  LINENUM, for that line in the current file,\n\
+  FILE:LINENUM, for that line in that file,\n\
+  +OFFSET, for that number of lines after the current line\n\
+           or the start of the range\n\
+  FUNCTION, for the first line in that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, for the instruction at that address.\n\
+\n\
+The breakpoint will stop execution of the inferior whenever it executes\n\
+an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
+range (including START-LOCATION and END-LOCATION)."));
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index a0fea21..fd7ea62 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -217,6 +217,10 @@ struct bp_target_info
      is used to determine the type of breakpoint to insert.  */
   CORE_ADDR placed_address;
 
+  /* If this is a ranged breakpoint, then this field contains the
+     length of the range that will be watched for execution.  */
+  int length;
+
   /* If the breakpoint lives in memory and reading that memory would
      give back the breakpoint, instead of the original contents, then
      the original contents are cached here.  Only SHADOW_LEN bytes of
@@ -325,7 +329,8 @@ struct bp_location
   CORE_ADDR address;
 
   /* For hardware watchpoints, the size of the memory region being
-     watched.  */
+     watched.  For hardware ranged breakpoints, the size of the
+     breakpoint range.  */
   int length;
 
   /* Type of hardware watchpoint.  */
@@ -383,7 +388,8 @@ struct breakpoint_ops
 
   /* Return non-zero if the debugger should tell the user that this
      breakpoint was hit.  */
-  int (*breakpoint_hit) (struct breakpoint *);
+  int (*breakpoint_hit) (const struct bp_location *, struct address_space *,
+			 CORE_ADDR);
 
   /* Tell how many hardware resources (debug registers) are needed
      for this breakpoint.  If this function is not provided, then
@@ -398,6 +404,20 @@ struct breakpoint_ops
      breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".
+
+     In the example below, the "address range" line was printed
+     by print_one_detail_ranged_breakpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw breakpoint  keep y              in main at test-watch.c:70
+	     address range: [0x10000458, 0x100004c7]
+
+   */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it
      (roughly speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a5eaa72..0f93850 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18727,9 +18727,27 @@ region using one of the following commands (@pxref{Expressions}):
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+@cindex ranged breakpoint
+PowerPC embedded processors support hardware accelerated
+@dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
+the inferior whenever it executes an instruction at any address within
+the range it specifies.  To set a ranged breakpoint in @value{GDBN},
+use the @code{break-range} command.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex break-range
+@item break-range @var{start-location}, @var{end-location}
+Set a breakpoint for an address range.
+@var{start-location} and @var{end-location} can specify a function name,
+a line number, an offset of lines from the current line or from the start
+location, or an address of an instruction (see @ref{Specify Location},
+for a list of all the possible ways to specify a @var{location}.)
+The breakpoint will stop execution of the inferior whenever it
+executes an instruction at any address within the specified range,
+(including @var{start-location} and @var{end-location}.)
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 049cde8..f0c7f61 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1637,6 +1637,19 @@ booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
   hw_breaks[i].hw_break = NULL;
 }
 
+/* Return the number of registers needed for a ranged breakpoint.  */
+
+static int
+ppc_linux_ranged_break_num_registers (struct target_ops *target)
+{
+  return ((have_ptrace_booke_interface ()
+	   && booke_debug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
+	  2 : -1);
+}
+
+/* Insert the hardware breakpoint described by BP_TGT.  Returns 0 for
+   success, 1 if hardware breakpoints are not supported or -1 for failure.  */
+
 static int
 ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 				  struct bp_target_info *bp_tgt)
@@ -1650,12 +1663,24 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is
+	 within the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_insert_point (&p, TIDGET (ptid));
 
@@ -1675,12 +1700,24 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is within
+	 the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_remove_point (&p, TIDGET (ptid));
 
@@ -2392,6 +2429,7 @@ _initialize_ppc_linux_nat (void)
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/target.c b/gdb/target.c
index aa59920..39702eb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -604,6 +604,7 @@ update_current_target (void)
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
+      /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
@@ -3505,6 +3506,21 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_ranged_break_num_registers (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_ranged_break_num_registers != NULL)
+      return t->to_ranged_break_num_registers (t);
+
+  return -1;
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
diff --git a/gdb/target.h b/gdb/target.h
index e19f7b7..7e12db6 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -450,6 +450,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_ranged_break_num_registers) (struct target_ops *);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -1366,6 +1367,11 @@ extern char *target_thread_name (struct thread_info *);
 #define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_remove_hw_breakpoint) (gdbarch, bp_tgt)
 
+/* Return number of debug registers needed for a ranged breakpoint,
+   or -1 if ranged breakpoints are not supported.  */
+
+extern int target_ranged_break_num_registers (void);
+
 /* Return non-zero if target knows the data address which triggered this
    target_stopped_by_watchpoint, in such case place it to *ADDR_P.  Only the
    INFERIOR_PTID task is being queried.  */


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-12  2:03       ` Thiago Jung Bauermann
@ 2011-03-12 16:44         ` Thiago Jung Bauermann
  2011-03-14 20:50           ` Ulrich Weigand
  2011-03-14 21:02         ` Ulrich Weigand
  1 sibling, 1 reply; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-03-12 16:44 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Fri, 2011-03-11 at 21:36 -0300, Thiago Jung Bauermann wrote:
> On Mon, 2011-02-28 at 17:52 +0100, Ulrich Weigand wrote:
> > Do we really need to make a new ui_out_ function for this; this
> > seems a bit of a special case for that.  Why don't you just generate
> > the output here?   (Note that here you might want to use a temporary
> > stream like the one you had in the above functions but never used
> > there ...)
> 
> I think I was using that function somewhere else in a previous
> incarnation of this patch series, so it stayed. I didn't think it was a
> problem since it is analogous to other functions in ui-out.c. 

I forgot to mention that in this version I don't add a new ui_out_
function and instead use ui_out_field_fmt in
print_one_detail_ranged_breakpoint. I didn't even need a temporary
stream.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-12 16:44         ` Thiago Jung Bauermann
@ 2011-03-14 20:50           ` Ulrich Weigand
  2011-03-16  6:07             ` Thiago Jung Bauermann
  0 siblings, 1 reply; 22+ messages in thread
From: Ulrich Weigand @ 2011-03-14 20:50 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:
> On Fri, 2011-03-11 at 21:36 -0300, Thiago Jung Bauermann wrote:
> > On Mon, 2011-02-28 at 17:52 +0100, Ulrich Weigand wrote:
> > > Do we really need to make a new ui_out_ function for this; this
> > > seems a bit of a special case for that.  Why don't you just generate
> > > the output here?   (Note that here you might want to use a temporary
> > > stream like the one you had in the above functions but never used
> > > there ...)
> > 
> > I think I was using that function somewhere else in a previous
> > incarnation of this patch series, so it stayed. I didn't think it was a
> > problem since it is analogous to other functions in ui-out.c. 
> 
> I forgot to mention that in this version I don't add a new ui_out_
> function and instead use ui_out_field_fmt in
> print_one_detail_ranged_breakpoint. I didn't even need a temporary
> stream.

Well yes, but by duplicating the logic how platform-specific addresses
are printed ...  I was hoping to avoid that.  The idea is that maybe
at some point in the future we will support more complex address output
formats (e.g. segmented addresses), and it would be good to have as few
place as possible that need to be changed to do so.

Thus I'd prefer to not duplicate the logic in ui_out_field_core_addr,
but rather just call it twice (using a temporary stream).

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-12  2:03       ` Thiago Jung Bauermann
  2011-03-12 16:44         ` Thiago Jung Bauermann
@ 2011-03-14 21:02         ` Ulrich Weigand
  2011-03-28 16:50           ` Thiago Jung Bauermann
  1 sibling, 1 reply; 22+ messages in thread
From: Ulrich Weigand @ 2011-03-14 21:02 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:
> On Mon, 2011-02-28 at 17:52 +0100, Ulrich Weigand wrote:
> > Thiago Jung Bauermann wrote:
> > > > This adds the SAY_WHERE parameter so that the caller will go ahead to
> > > > add location information.  However, for a range breakpoint, this will
> > > > just be the start of the range, which may or may not be particularly
> > > > useful ...   Shouldn't we either:
> > > > - output the full range (start and end),  or
> > > > - output nothing ... we'll see the actual location where we stopped anyway
> > > > 
> > > > (Either way, the API change to add SAY_WHERE is no longer needed.)
> > > 
> > > I think it's useful. You have a point in that it makes more sense to
> > > print the end of the range as well. I'd have to extend struct breakpoint
> > > to save the source file and line number of the end of the range if I
> > > were to print them. I'm not sure it's worth it, so I changed
> > > print_mention_ranged_breakpoint to print only the start and end address
> > > of the range. And dropped the say_where argument. What do you think? 
> > 
> > Don't you have to know the end of the range anyway, in order to be
> > able to re-set the breakpoint?
> 
> I was thinking of the struct breakpoint's source_file and line_number,
> which are used mostly for printing (clear_command uses it for finding
> breakpoints). For print_mention_ranged_breakpoint I'd need
> source_file_range_end and line_number_range_end, but decided against it.
> 
> But now that you mention breakpoint re-setting, I just realised that I
> need to add addr_string_range_end and make breakpoint_re_set_one use it.
> As the patch currently stands, ranged breakpoints will be dropped when
> loading new binaries... I'm currently working on this but decided to
> send this patch as it is since it addresses all the other points you
> raised.

Well, but you do have this:

 static void
 print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
 {
   fprintf_unfiltered (fp, "break-range %s", b->exp_string);
 }

So I thought b->exp_string would already include the original start and
end, but simply in an un-parsed fashion.   If this could maybe be formatted
consistently, you might be able to use it for print_details as well, I guess.

> > It seems oddly asymmetrical to use parse_breakpoint_sals above but
> > decode_line_1 here.  Shouldn't start and end of the range use the
> > same symtab defaulting rules and other extra treatment done by
> > parse_breakpoint_sals?
> 
> No, the end location should default to the same file and line number as
> the start location. This makes it possible to have ranges like:
> 
> (gdb) break-range foo.c:27, +14
> 
> Had I used parse_breakpoint_sals, GDB would interpret "+14" as "14 lines
> from the current file and line number", and not "14 lines from the start
> location". As for the extra treatment, I had a look at them before and
> didn't think they applied in the context of resolving the end location.

Ah, good point, this does make sense.  Maybe a brief comment in the source
to that effect would be useful here?

> This was pointed out to me by Jan when reviewing another patch [1]:
> 
> > > --- a/gdb/target.c
> > > +++ b/gdb/target.c
> > > @@ -601,11 +601,16 @@ update_current_target (void)
> > >        INHERIT (to_files_info, t);
> > >        INHERIT (to_insert_breakpoint, t);
> > >        INHERIT (to_remove_breakpoint, t);
> > > +      INHERIT (to_can_use_special_hw_point, t);
> > 
> > There are now two target interface styles in use.  This inheriting one and the
> > runtime-inheriting one (see target_pid_to_str and others).  I was told the
> > target_pid_to_str style is now preferred and it makes sense to me.  Please
> > convert the new target vector methods to the new style.
> 
> So I just followed his advice and used the new method instead of the
> deprecated one which is used by the other breakpoint-related functions.

I agree in general that new target methods should use the new style.  The only
issue that makes me a bit nervous is that the two styles do have slightly
different effects (the struct target_ops that is passed in to the callback
may be a different one); so I'm wondering if it is a good idea to mix the
two methods within a group of closely related target methods ...

But then again, in this particular case it probably doesn't matter much,
as typical implementations of your newly added callback ought to be
straightforward, and probably won't care about the target_ops they get.
So I guess I withdraw my objection :-)

The rest of the patch looks fine to me now.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-14 20:50           ` Ulrich Weigand
@ 2011-03-16  6:07             ` Thiago Jung Bauermann
  2011-03-16 18:00               ` Ulrich Weigand
  0 siblings, 1 reply; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-03-16  6:07 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Mon, 2011-03-14 at 21:01 +0100, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> > I forgot to mention that in this version I don't add a new ui_out_
> > function and instead use ui_out_field_fmt in
> > print_one_detail_ranged_breakpoint. I didn't even need a temporary
> > stream.
> 
> Well yes, but by duplicating the logic how platform-specific addresses
> are printed ...  I was hoping to avoid that.  The idea is that maybe
> at some point in the future we will support more complex address output
> formats (e.g. segmented addresses), and it would be good to have as few
> place as possible that need to be changed to do so.
> 
> Thus I'd prefer to not duplicate the logic in ui_out_field_core_addr,
> but rather just call it twice (using a temporary stream).

ui_out_field_core_addr takes a struct ui_out, so I don't know how to
make it print to a temporary stream so I can call it twice from
print_one_detail_ranged_breakpoint without having to specify a different
field name in each call. What about putting the address-printing logic
in a function which uses a temporary stream, then make both
ui_out_field_core_addr and print_one_detail_ranged_breakpoint use it?
The patch below implements the idea.

OTOH, does it make sense to worry about fields at all? The string I'm
printing doesn't belong to any column in the info breakpoint output. It
is an independent, additional line below the line with breakpoint
information, at least that's how I think of it. Then perhaps I shouldn't
be calling any ui_out_field_ function at all, but rather something else
which prints an address to a ui_out...
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index d36c663..a93f09d 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -8386,28 +8386,25 @@ static void
 print_one_detail_ranged_breakpoint (const struct breakpoint *b,
 				    struct ui_out *uiout)
 {
-  int addr_bit, hex_width;
   CORE_ADDR address_start, address_end;
   struct bp_location *bl = b->loc;
+  struct ui_stream *stb = ui_out_stream_new (uiout);
+  struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
 
   gdb_assert (bl);
 
-  addr_bit = gdbarch_addr_bit (bl->gdbarch);
-  hex_width = addr_bit / 4;
   address_start = bl->address;
   address_end = address_start + bl->length - 1;
 
-  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
-    {
-      address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
-      address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
-    }
-
   ui_out_text (uiout, "\taddress range: ");
-  ui_out_field_fmt (uiout, "addr", "[%s, %s]",
-		    hex_string_custom (address_start, hex_width),
-		    hex_string_custom (address_end, hex_width));
-  ui_out_text (uiout, "\n");
+  fputs_unfiltered ("[", stb->stream);
+  print_core_address (stb->stream, bl->gdbarch, address_start);
+  fputs_unfiltered (", ", stb->stream);
+  print_core_address (stb->stream, bl->gdbarch, address_end);
+  fputs_unfiltered ("]\n", stb->stream);
+  ui_out_field_stream (uiout, "addr", stb);
+
+  do_cleanups (cleanup);
 }
 
 /* Implement the "print_mention" breakpoint_ops method for
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 2cd1a54..c2962c3 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -486,15 +486,12 @@ ui_out_field_fmt_int (struct ui_out *uiout,
   uo_field_int (uiout, fldno, input_width, input_align, fldname, value);
 }
 
+/* This function is described in "ui-out.h".  */
+
 void
-ui_out_field_core_addr (struct ui_out *uiout,
-			const char *fldname,
-			struct gdbarch *gdbarch,
-			CORE_ADDR address)
+print_core_address (struct ui_file *stb, struct gdbarch *gdbarch,
+		    CORE_ADDR address)
 {
-  /* Maximum size string returned by hex_string_custom is 50 chars.
-     This buffer must be bigger than that, for safety.  */
-  char addstr[64];
   int addr_bit = gdbarch_addr_bit (gdbarch);
 
   if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
@@ -504,11 +501,23 @@ ui_out_field_core_addr (struct ui_out *uiout,
      that returns the language localized string formatted to a width
      based on gdbarch_addr_bit.  */
   if (addr_bit <= 32)
-    strcpy (addstr, hex_string_custom (address, 8));
+    fputs_unfiltered (hex_string_custom (address, 8), stb);
   else
-    strcpy (addstr, hex_string_custom (address, 16));
+    fputs_unfiltered (hex_string_custom (address, 16), stb);
+}
+
+void
+ui_out_field_core_addr (struct ui_out *uiout,
+			const char *fldname,
+			struct gdbarch *gdbarch,
+			CORE_ADDR address)
+{
+  struct ui_stream *stb = ui_out_stream_new (uiout);
+  struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
 
-  ui_out_field_string (uiout, fldname, addstr);
+  print_core_address (stb->stream, gdbarch, address);
+  ui_out_field_stream (uiout, fldname, stb);
+  do_cleanups (cleanup);
 }
 
 void
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 5265902..09442f2 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -282,4 +282,9 @@ extern struct ui_out *ui_out_new (struct ui_out_impl *impl,
 
 extern int ui_out_redirect (struct ui_out *uiout, struct ui_file *outstream);
 
+/* Print ADDRESS in hexadecimal notation to the given STREAM.  */
+
+extern void print_core_address (struct ui_file *stb,
+				struct gdbarch *gdbarch, CORE_ADDR address);
+
 #endif /* UI_OUT_H */


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-16  6:07             ` Thiago Jung Bauermann
@ 2011-03-16 18:00               ` Ulrich Weigand
  0 siblings, 0 replies; 22+ messages in thread
From: Ulrich Weigand @ 2011-03-16 18:00 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:
> On Mon, 2011-03-14 at 21:01 +0100, Ulrich Weigand wrote:
> > Thus I'd prefer to not duplicate the logic in ui_out_field_core_addr,
> > but rather just call it twice (using a temporary stream).
> 
> ui_out_field_core_addr takes a struct ui_out, so I don't know how to
> make it print to a temporary stream so I can call it twice from
> print_one_detail_ranged_breakpoint without having to specify a different
> field name in each call. What about putting the address-printing logic
> in a function which uses a temporary stream, then make both
> ui_out_field_core_addr and print_one_detail_ranged_breakpoint use it?
> The patch below implements the idea.

OK, I like that ...  Maybe it would be even better to move the new
routine into utils.c next to paddress, the only other routine to
format addresses at the moment?

This could e.g. take the form of a routine

  const char *
  paddress_padded (struct gdbarch *gdbarch, CORE_ADDR addr)

which returns a string just like paddress, but padded to at least 8
or 16 characters, depending on the address size.

ui_out_field_core_addr (and print_one_detail_ranged_breakpoint) could
then just use this to print into a temporary stream ...

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-14 21:02         ` Ulrich Weigand
@ 2011-03-28 16:50           ` Thiago Jung Bauermann
  2011-03-29 13:10             ` Ulrich Weigand
  0 siblings, 1 reply; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-03-28 16:50 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

Hi Ulrich,

In addition to the changes I mention below, in this patch I changed
breakpoint_re_set_one to properly handle ranged breakpoints (something I
noticed I wasn't doing in previous versions of the patch). For this
reason, the patch depends on the cleanup and refactoring patches I
posted earlier:

http://sourceware.org/ml/gdb-patches/2011-03/msg00978.html
http://sourceware.org/ml/gdb-patches/2011-03/msg01127.html

The change is actually in reset_breakpoint and
update_breakpoint_locations. I also had to add addr_string_range_end to
struct breakpoint.

(Documentation changes already approved.)

On Mon, 2011-03-14 at 21:22 +0100, Ulrich Weigand wrote: 
> Thiago Jung Bauermann wrote:
> > On Mon, 2011-02-28 at 17:52 +0100, Ulrich Weigand wrote:
> > > Thiago Jung Bauermann wrote:
> > > > I think it's useful. You have a point in that it makes more sense to
> > > > print the end of the range as well. I'd have to extend struct breakpoint
> > > > to save the source file and line number of the end of the range if I
> > > > were to print them. I'm not sure it's worth it, so I changed
> > > > print_mention_ranged_breakpoint to print only the start and end address
> > > > of the range. And dropped the say_where argument. What do you think? 
> > > 
> > > Don't you have to know the end of the range anyway, in order to be
> > > able to re-set the breakpoint?
> > 
> > I was thinking of the struct breakpoint's source_file and line_number,
> > which are used mostly for printing (clear_command uses it for finding
> > breakpoints). For print_mention_ranged_breakpoint I'd need
> > source_file_range_end and line_number_range_end, but decided against it.
> > 
> > But now that you mention breakpoint re-setting, I just realised that I
> > need to add addr_string_range_end and make breakpoint_re_set_one use it.
> > As the patch currently stands, ranged breakpoints will be dropped when
> > loading new binaries... I'm currently working on this but decided to
> > send this patch as it is since it addresses all the other points you
> > raised.
> 
> Well, but you do have this:
> 
>  static void
>  print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
>  {
>    fprintf_unfiltered (fp, "break-range %s", b->exp_string);
>  }
> 
> So I thought b->exp_string would already include the original start and
> end, but simply in an un-parsed fashion.   If this could maybe be formatted
> consistently, you might be able to use it for print_details as well, I guess.

Yes, but I'm not looking forward to take arbitrary user input and try to
format it consistently. :-)

In this patch I had to modify print_recreate_ranged_breakpoint to use
addr_string_range_end since I don't use exp_string anymore. I could
change print_mention_ranged_breakpoint to use it too, since it's
formatted consistently. However, breakpoint.c:mention doesn't use
b->addr_string and instead uses b->source_file and b->line_number, so
I'm not sure if I should use b->addr_string_range_end. I left that out
for now.

> > > It seems oddly asymmetrical to use parse_breakpoint_sals above but
> > > decode_line_1 here.  Shouldn't start and end of the range use the
> > > same symtab defaulting rules and other extra treatment done by
> > > parse_breakpoint_sals?
> > 
> > No, the end location should default to the same file and line number as
> > the start location. This makes it possible to have ranges like:
> > 
> > (gdb) break-range foo.c:27, +14
> > 
> > Had I used parse_breakpoint_sals, GDB would interpret "+14" as "14 lines
> > from the current file and line number", and not "14 lines from the start
> > location". As for the extra treatment, I had a look at them before and
> > didn't think they applied in the context of resolving the end location.
> 
> Ah, good point, this does make sense.  Maybe a brief comment in the source
> to that effect would be useful here?

Done:

+  /* We call decode_line_n1 directly here instead of using
+     parse_breakpoint_sals because we need to specify the start location's
+     symtab and line as the default symtab and line for the end of the
+     range.  This makes it possible to have ranges like "foo.c:27, +14",
+     where +14 means 14 lines from the start location.  */
+  sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
+                           &canonical_end, NULL);

> > This was pointed out to me by Jan when reviewing another patch [1]:
> > 
> > > > --- a/gdb/target.c
> > > > +++ b/gdb/target.c
> > > > @@ -601,11 +601,16 @@ update_current_target (void)
> > > >        INHERIT (to_files_info, t);
> > > >        INHERIT (to_insert_breakpoint, t);
> > > >        INHERIT (to_remove_breakpoint, t);
> > > > +      INHERIT (to_can_use_special_hw_point, t);
> > > 
> > > There are now two target interface styles in use.  This inheriting one and the
> > > runtime-inheriting one (see target_pid_to_str and others).  I was told the
> > > target_pid_to_str style is now preferred and it makes sense to me.  Please
> > > convert the new target vector methods to the new style.
> > 
> > So I just followed his advice and used the new method instead of the
> > deprecated one which is used by the other breakpoint-related functions.
> 
> I agree in general that new target methods should use the new style.  The only
> issue that makes me a bit nervous is that the two styles do have slightly
> different effects (the struct target_ops that is passed in to the callback
> may be a different one); so I'm wondering if it is a good idea to mix the
> two methods within a group of closely related target methods ...
> 
> But then again, in this particular case it probably doesn't matter much,
> as typical implementations of your newly added callback ought to be
> straightforward, and probably won't care about the target_ops they get.
> So I guess I withdraw my objection :-)
> 
> The rest of the patch looks fine to me now.

Great! What do you think of this version? No regressions on ppc-linux,
ppc64-linux or i386-linux.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-03-27  Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

	Implement support for PowerPC BookE ranged breakpoints.

gdb/
	* NEWS: Mention support for ranged breakpoints on embedded PowerPC.
	* breakpoint.h (struct bp_target_info) <length>: New member
	variable.
	(struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
	instead of struct breakpoint as argument, and also add ASPACE
	and BP_ADDR arguments.  Update all callers.
	(struct breakpoint_ops) <print_one_detail>: New method.
	(struct breakpoint) <addr_string_range_end>: New member variable.
	* breakpoint.c (breakpoint_location_address_match): Add function
	prototype.
	(insert_bp_location): Set bl->target_info.length.
	(breakpoint_here_p): Call breakpoint_location_address_match.
	(moribund_breakpoint_here_p): Likewise.
	(regular_breakpoint_inserted_here_p): Likewise.
	(breakpoint_thread_match): Likewise.
	(bpstat_stop_status): Likewise.
	(bpstat_check_location): Move call to
	breakpoint_ops.breakpoint_hit to the top.
	(print_one_breakpoint_location): Call
	breakpoint_ops.print_one_detail if available.
	(breakpoint_address_match_range): New function.
	(breakpoint_location_address_match): Likewise.
	(breakpoint_locations_match): Compare the length field of the
	locations too.
	(hw_breakpoint_used_count): Count resources used by all locations
	in a breakpoint, and use breakpoint_ops.resources_needed if
	available.
	(breakpoint_hit_ranged_breakpoint): New function.
	(resources_needed_ranged_breakpoint): Likewise.
	(print_it_ranged_breakpoint): Likewise.
	(print_one_ranged_breakpoint): Likewise.
	(print_one_detail_ranged_breakpoint): Likewise.
	(print_mention_ranged_breakpoint): Likewise.
	(print_recreate_ranged_breakpoint): Likewise.
	(ranged_breakpoint_ops): New structure.
	(find_breakpoint_range_end): New function.
	(break_range_command): Likewise.
	(delete_breakpoint): Free addr_string_range_end.
	(update_breakpoint_locations): Add SALS_END argument.  Calculate
	breakpoint length if a non-zero SALS_END is given.  Call
	breakpoint_locations_match instead of breakpoint_address_match.
	(reset_breakpoint): Find SaL of the end of the range if B is a
	ranged breakpoint.
	(_initialize_breakpoint): Register break-range command.
	* defs.h (print_core_address): Add function prototype.
	* ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
	function.
	(ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
	(ppc_linux_remove_hw_breakpoint): Likewise.
	(_initialize_ppc_linux_nat): Initialize
	to_ranged_break_num_registers.
	* target.c (update_current_target): Add comment about
	to_ranged_break_num_registers.
	(target_ranged_break_num_registers): New function.
	* target.h (struct target_ops) <to_ranged_break_num_registers>:
	New method.
	(target_ranged_break_num_registers): Add function prototype.
	* ui-out.c (ui_out_field_core_addr): Move address-printing logic to ...
	* utils.c (print_core_address): ... here.

gdb/doc/
	* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 2288497..a777042 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -156,6 +156,12 @@
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
+  which stop execution of the inferior whenever it executes an instruction
+  at any address within the specified range.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 5728ac8..2063f3d 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10925,6 +10925,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10964,6 +10965,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* resources_needed */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -11001,6 +11003,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* resources_needed */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index df8bb99..13c3574 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -131,6 +131,10 @@ static int breakpoint_address_match (struct address_space *aspace1,
 static int watchpoint_locations_match (struct bp_location *loc1,
 				       struct bp_location *loc2);
 
+static int breakpoint_location_address_match (struct bp_location *bl,
+					      struct address_space *aspace,
+					      CORE_ADDR addr);
+
 static void breakpoints_info (char *, int);
 
 static void watchpoints_info (char *, int);
@@ -1522,6 +1526,7 @@ insert_bp_location (struct bp_location *bl,
   memset (&bl->target_info, 0, sizeof (bl->target_info));
   bl->target_info.placed_address = bl->address;
   bl->target_info.placed_address_space = bl->pspace->aspace;
+  bl->target_info.length = bl->length;
 
   if (bl->loc_type == bp_loc_software_breakpoint
       || bl->loc_type == bp_loc_hardware_breakpoint)
@@ -2784,11 +2789,10 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
 	  && bl->loc_type != bp_loc_hardware_breakpoint)
 	continue;
 
-      /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL.  */
+      /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL.  */
       if ((breakpoint_enabled (bl->owner)
 	   || bl->owner->enable_state == bp_permanent)
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2813,8 +2817,7 @@ moribund_breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
   int ix;
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
-    if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				  aspace,  pc))
+    if (breakpoint_location_address_match (loc, aspace, pc))
       return 1;
 
   return 0;
@@ -2838,8 +2841,7 @@ regular_breakpoint_inserted_here_p (struct address_space *aspace,
 	continue;
 
       if (bl->inserted
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2956,8 +2958,7 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
 	  && bl->owner->enable_state != bp_permanent)
 	continue;
 
-      if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
-				     aspace, pc))
+      if (!breakpoint_location_address_match (bl, aspace, pc))
 	continue;
 
       if (bl->owner->thread != -1)
@@ -3847,6 +3848,9 @@ bpstat_check_location (const struct bp_location *bl,
   /* BL is from existing struct breakpoint.  */
   gdb_assert (b != NULL);
 
+  if (b->ops && b->ops->breakpoint_hit)
+    return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+
   /* By definition, the inferior does not report stops at
      tracepoints.  */
   if (is_tracepoint (b))
@@ -3875,7 +3879,7 @@ bpstat_check_location (const struct bp_location *bl,
   if (is_hardware_watchpoint (b)
       && b->watchpoint_triggered == watch_triggered_no)
     return 0;
-  
+
   if (b->type == bp_hardware_breakpoint)
     {
       if (bl->address != bp_addr)
@@ -3886,13 +3890,6 @@ bpstat_check_location (const struct bp_location *bl,
 	return 0;
     }
 
-  if (b->type == bp_catchpoint)
-    {
-      gdb_assert (b->ops != NULL && b->ops->breakpoint_hit != NULL);
-      if (!b->ops->breakpoint_hit (b))
-        return 0;
-    }
-     
   return 1;
 }
 
@@ -4254,8 +4251,7 @@ bpstat_stop_status (struct address_space *aspace,
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
     {
-      if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				    aspace, bp_addr))
+      if (breakpoint_location_address_match (loc, aspace, bp_addr))
 	{
 	  bs = bpstat_alloc (loc, &bs_link);
 	  /* For hits of moribund locations, we should just proceed.  */
@@ -4906,9 +4902,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5490,6 +5489,39 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
 	  && addr1 == addr2);
 }
 
+/* Returns true if {ASPACE2,ADDR2} falls within the range determined by
+   {ASPACE1,ADDR1,LEN1}.  In most targets, this can only be true if ASPACE1
+   matches ASPACE2.  On targets that have global breakpoints, the address
+   space doesn't really matter.  */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+				int len1, struct address_space *aspace2,
+				CORE_ADDR addr2)
+{
+  return ((gdbarch_has_global_breakpoints (target_gdbarch)
+	   || aspace1 == aspace2)
+	  && addr2 >= addr1 && addr2 < addr1 + len1);
+}
+
+/* Returns true if {ASPACE,ADDR} matches the breakpoint BL.  BL may be
+   a ranged breakpoint.  In most targets, a match happens only if ASPACE
+   matches the breakpoint's address space.  On targets that have global
+   breakpoints, the address space doesn't really matter.  */
+
+static int
+breakpoint_location_address_match (struct bp_location *bl,
+				   struct address_space *aspace,
+				   CORE_ADDR addr)
+{
+  return (breakpoint_address_match (bl->pspace->aspace, bl->address,
+				    aspace, addr)
+	  || (bl->length
+	      && breakpoint_address_match_range (bl->pspace->aspace,
+						 bl->address, bl->length,
+						 aspace, addr)));
+}
+
 /* Assuming LOC1 and LOC2's types' have meaningful target addresses
    (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
    represent the same location.  */
@@ -5512,8 +5544,10 @@ breakpoint_locations_match (struct bp_location *loc1,
   else if (hw_point1)
     return watchpoint_locations_match (loc1, loc2);
   else
-    return breakpoint_address_match (loc1->pspace->aspace, loc1->address,
-				     loc2->pspace->aspace, loc2->address);
+    /* We compare bp_location.length in order to cover ranged breakpoints.  */
+    return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
+				     loc2->pspace->aspace, loc2->address)
+	    && loc1->length == loc2->length);
 }
 
 static void
@@ -6122,9 +6156,10 @@ remove_catch_fork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_fork (struct breakpoint *b)
+breakpoint_hit_catch_fork (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_forked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for fork
@@ -6193,6 +6228,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -6219,9 +6255,10 @@ remove_catch_vfork (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_vfork (struct breakpoint *b)
+breakpoint_hit_catch_vfork (const struct bp_location *bl,
+			    struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_vforked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for vfork
@@ -6289,6 +6326,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6378,12 +6416,14 @@ remove_catch_syscall (struct bp_location *bl)
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_syscall (struct breakpoint *b)
+breakpoint_hit_catch_syscall (const struct bp_location *bl,
+			      struct address_space *aspace, CORE_ADDR bp_addr)
 {
   /* We must check if we are catching specific syscalls in this
      breakpoint.  If we are, then we must guarantee that the called
      syscall is the same syscall we are catching.  */
   int syscall_number = 0;
+  const struct breakpoint *b = bl->owner;
 
   if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
     return 0;
@@ -6452,7 +6492,7 @@ print_it_catch_syscall (struct breakpoint *b)
 
 static void
 print_one_catch_syscall (struct breakpoint *b,
-                         struct bp_location **last_loc)
+			 struct bp_location **last_loc)
 {
   struct value_print_options opts;
 
@@ -6573,6 +6613,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6668,9 +6709,10 @@ remove_catch_exec (struct bp_location *bl)
 }
 
 static int
-breakpoint_hit_catch_exec (struct breakpoint *b)
+breakpoint_hit_catch_exec (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_execd (inferior_ptid, &b->exec_pathname);
+  return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
 }
 
 static enum print_stop_action
@@ -6727,6 +6769,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   NULL, /* resources_needed */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6750,13 +6793,22 @@ create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
 static int
 hw_breakpoint_used_count (void)
 {
-  struct breakpoint *b;
   int i = 0;
+  struct breakpoint *b;
+  struct bp_location *bl;
 
   ALL_BREAKPOINTS (b)
   {
     if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
-      i++;
+      for (bl = b->loc; bl; bl = bl->next)
+	{
+	  /* Special types of hardware breakpoints may use more than
+	     one register.  */
+	  if (b->ops && b->ops->resources_needed)
+	    i += b->ops->resources_needed (bl);
+	  else
+	    i++;
+	}
   }
 
   return i;
@@ -8219,6 +8271,309 @@ stopat_command (char *arg, int from_tty)
     break_command_1 (arg, 0, from_tty);
 }
 
+/* Implement the "breakpoint_hit" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+				  struct address_space *aspace,
+				  CORE_ADDR bp_addr)
+{
+  return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+					 bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+  return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  annotate_breakpoint (b->number);
+  if (b->disposition == disp_del)
+    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+  else
+    ui_out_text (uiout, "\nRanged breakpoint ");
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+    }
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
+
+  return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+			     struct bp_location **last_loc)
+{
+  struct bp_location *bl = b->loc;
+  struct value_print_options opts;
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  get_user_print_options (&opts);
+
+  if (opts.addressprint)
+    /* We don't print the address range here, it will be printed later
+       by print_one_detail_ranged_breakpoint.  */
+    ui_out_field_skip (uiout, "addr");
+  annotate_field (5);
+  print_breakpoint_location (b, bl);
+  *last_loc = bl;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  CORE_ADDR address_start, address_end;
+  struct bp_location *bl = b->loc;
+  struct ui_stream *stb = ui_out_stream_new (uiout);
+  struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
+
+  gdb_assert (bl);
+
+  address_start = bl->address;
+  address_end = address_start + bl->length - 1;
+
+  ui_out_text (uiout, "\taddress range: ");
+  fprintf_unfiltered (stb->stream, "[%s, %s]",
+		      print_core_address (bl->gdbarch, address_start),
+		      print_core_address (bl->gdbarch, address_end));
+  ui_out_field_stream (uiout, "addr", stb);
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (cleanup);
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (bl);
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  if (ui_out_is_mi_like_p (uiout))
+    return;
+
+  printf_filtered (_("Hardware assisted ranged breakpoint %d from %s to %s."),
+		   b->number, paddress (bl->gdbarch, bl->address),
+		   paddress (bl->gdbarch, bl->address + bl->length - 1));
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
+		      b->addr_string_range_end);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints.  */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+  NULL, /* insert */
+  NULL, /* remove */
+  breakpoint_hit_ranged_breakpoint,
+  resources_needed_ranged_breakpoint,
+  print_it_ranged_breakpoint,
+  print_one_ranged_breakpoint,
+  print_one_detail_ranged_breakpoint,
+  print_mention_ranged_breakpoint,
+  print_recreate_ranged_breakpoint
+};
+
+/* Find the address where the end of the breakpoint range should be
+   placed, given the SAL of the end of the range.  This is so that if
+   the user provides a line number, the end of the range is set to the
+   last instruction of the given line.  */
+
+static CORE_ADDR
+find_breakpoint_range_end (struct symtab_and_line sal)
+{
+  CORE_ADDR end;
+
+  /* If the user provided a PC value, use it.  Otherwise,
+     find the address of the end of the given location.  */
+  if (sal.explicit_pc)
+    end = sal.pc;
+  else
+    {
+      int ret;
+      CORE_ADDR start;
+
+      ret = find_line_pc_range (sal, &start, &end);
+      if (!ret)
+	error (_("Could not find location of the end of the range."));
+
+      /* find_line_pc_range returns the start of the next line.  */
+      end--;
+    }
+
+  return end;
+}
+
+/* Implement the "break-range" CLI command.  */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+  char *arg_start, *addr_string_start, *addr_string_end;
+  struct linespec_result canonical_start, canonical_end;
+  int bp_count, can_use_bp, length;
+  CORE_ADDR end;
+  struct breakpoint *b;
+  struct symtab_and_line sal_start, sal_end;
+  struct symtabs_and_lines sals_start, sals_end;
+  struct cleanup *cleanup_bkpt;
+
+  /* We don't support software ranged breakpoints.  */
+  if (target_ranged_break_num_registers () < 0)
+    error (_("This target does not support hardware ranged breakpoints."));
+
+  bp_count = hw_breakpoint_used_count ();
+  bp_count += target_ranged_break_num_registers ();
+  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+						   bp_count, 0);
+  if (can_use_bp < 0)
+    error (_("Hardware breakpoints used exceeds limit."));
+
+  if (arg == NULL || arg[0] == '\0')
+    error(_("No address range specified."));
+
+  sals_start.sals = NULL;
+  sals_start.nelts = 0;
+  init_linespec_result (&canonical_start);
+
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  parse_breakpoint_sals (&arg, &sals_start, &canonical_start, NULL);
+
+  sal_start = sals_start.sals[0];
+  addr_string_start = canonical_start.canonical[0];
+  cleanup_bkpt = make_cleanup (xfree, addr_string_start);
+  xfree (sals_start.sals);
+  xfree (canonical_start.canonical);
+
+  if (arg[0] != ',')
+    error (_("Too few arguments."));
+  else if (sals_start.nelts == 0)
+    error (_("Could not find location of the beginning of the range."));
+  else if (sals_start.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  resolve_sal_pc (&sal_start);
+
+  arg++;	/* Skip the comma.  */
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  /* Parse the end location.  */
+
+  sals_end.sals = NULL;
+  sals_end.nelts = 0;
+  init_linespec_result (&canonical_end);
+  arg_start = arg;
+
+  /* We call decode_line_n1 directly here instead of using
+     parse_breakpoint_sals because we need to specify the start location's
+     symtab and line as the default symtab and line for the end of the
+     range.  This makes it possible to have ranges like "foo.c:27, +14",
+     where +14 means 14 lines from the start location.  */
+  sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
+			    &canonical_end, NULL);
+
+  /* canonical_end can be NULL if it was of the form "*0xdeadbeef".  */
+  if (canonical_end.canonical == NULL)
+    canonical_end.canonical = xcalloc (1, sizeof (char **));
+  /* Add the string if not present.  */
+  if (arg_start != arg && canonical_end.canonical[0] == NULL)
+    canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
+
+  sal_end = sals_end.sals[0];
+  addr_string_end = canonical_end.canonical[0];
+  make_cleanup (xfree, addr_string_end);
+  xfree (sals_end.sals);
+  xfree (canonical_end.canonical);
+
+  if (sals_end.nelts == 0)
+    error (_("Could not find location of the end of the range."));
+  else if (sals_end.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  resolve_sal_pc (&sal_end);
+
+  end = find_breakpoint_range_end (sal_end);
+  if (sal_start.pc > end)
+    error (_("Invalid address range, end preceeds start."));
+
+  length = end - sal_start.pc + 1;
+  if (length < 0)
+    /* Length overflowed.  */
+    error (_("Address range too large."));
+  else if (length == 1)
+    {
+      /* This range is simple enough to be handled by
+	 the `hbreak' command.  */
+      hbreak_command (addr_string_start, 1);
+
+      do_cleanups (cleanup_bkpt);
+
+      return;
+    }
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (get_current_arch (), sal_start,
+			  bp_hardware_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->disposition = disp_donttouch;
+  b->addr_string = addr_string_start;
+  b->addr_string_range_end = addr_string_end;
+  b->ops = &ranged_breakpoint_ops;
+  b->loc->length = length;
+
+  discard_cleanups (cleanup_bkpt);
+
+  mention (b);
+  update_global_location_list (1);
+}
+
 /*  Return non-zero if EXP is verified as constant.  Returned zero
     means EXP is variable.  Also the constant detection may fail for
     some constant expressions and in such case still falsely return
@@ -8371,6 +8726,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   resources_needed_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
@@ -9149,6 +9505,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* resources_needed */
   print_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -10087,6 +10444,7 @@ delete_breakpoint (struct breakpoint *bpt)
   xfree (bpt->cond_string);
   xfree (bpt->cond_exp);
   xfree (bpt->addr_string);
+  xfree (bpt->addr_string_range_end);
   xfree (bpt->exp);
   xfree (bpt->exp_string);
   xfree (bpt->exp_string_reparse);
@@ -10381,14 +10739,21 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
   return sal;
 }
 
+/* Create new breakpoint locations for B (a hardware or software breakpoint)
+   based on SALS and SALS_END.  If SALS_END.NELTS is not zero, then B is
+   a ranged breakpoint.  */
+
 static void
 update_breakpoint_locations (struct breakpoint *b,
-			     struct symtabs_and_lines sals)
+			     struct symtabs_and_lines sals,
+			     struct symtabs_and_lines sals_end)
 {
   int i;
-  char *s;
   struct bp_location *existing_locations = b->loc;
 
+  /* Ranged breakpoints have only one start location and one end location.  */
+  gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+
   /* If there's no new locations, and all existing locations are
      pending, don't do anything.  This optimizes the common case where
      all locations are in the same shared library, that was unloaded.
@@ -10409,6 +10774,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	 old symtab.  */
       if (b->cond_string != NULL)
 	{
+	  char *s;
 	  struct gdb_exception e;
 
 	  s = b->cond_string;
@@ -10435,6 +10801,13 @@ update_breakpoint_locations (struct breakpoint *b,
 
       if (b->line_number == 0)
 	b->line_number = sals.sals[i].line;
+
+      if (sals_end.nelts)
+	{
+	  CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
+
+	  new_loc->length = end - sals.sals[0].pc + 1;
+	}
     }
 
   /* Update locations of permanent breakpoints.  */
@@ -10460,8 +10833,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	    if (have_ambiguous_names)
 	      {
 		for (; l; l = l->next)
-		  if (breakpoint_address_match (e->pspace->aspace, e->address,
-						l->pspace->aspace, l->address))
+		  if (breakpoint_locations_match (e, l))
 		    {
 		      l->enabled = 0;
 		      break;
@@ -10571,8 +10943,9 @@ static void
 reset_breakpoint (struct breakpoint *b)
 {
   int found;
-  struct symtabs_and_lines sals;
+  struct symtabs_and_lines sals, sals_end;
   struct symtabs_and_lines expanded = {0};
+  struct symtabs_and_lines expanded_end = {0};
   struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
 
   input_radix = b->input_radix;
@@ -10587,7 +10960,17 @@ reset_breakpoint (struct breakpoint *b)
       expanded = expand_line_sal_maybe (sals.sals[0]);
     }
 
-  update_breakpoint_locations (b, expanded);
+  if (b->addr_string_range_end)
+    {
+      sals_end = addr_string_to_sals (b, b->addr_string_range_end, &found);
+      if (found)
+	{
+	  make_cleanup (xfree, sals_end.sals);
+	  expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+	}
+    }
+
+  update_breakpoint_locations (b, expanded, expanded_end);
   do_cleanups (cleanups);
 }
 
@@ -12615,7 +12998,23 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
 			   &show_always_inserted_mode,
 			   &breakpoint_set_cmdlist,
 			   &breakpoint_show_cmdlist);
-  
+
+  add_com ("break-range", class_breakpoint, break_range_command, _("\
+Set a breakpoint for an address range.\n\
+break-range START-LOCATION, END-LOCATION\n\
+where START-LOCATION and END-LOCATION can be one of the following:\n\
+  LINENUM, for that line in the current file,\n\
+  FILE:LINENUM, for that line in that file,\n\
+  +OFFSET, for that number of lines after the current line\n\
+           or the start of the range\n\
+  FUNCTION, for the first line in that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, for the instruction at that address.\n\
+\n\
+The breakpoint will stop execution of the inferior whenever it executes\n\
+an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
+range (including START-LOCATION and END-LOCATION)."));
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index d5af928..95eff4c 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -218,6 +218,10 @@ struct bp_target_info
      is used to determine the type of breakpoint to insert.  */
   CORE_ADDR placed_address;
 
+  /* If this is a ranged breakpoint, then this field contains the
+     length of the range that will be watched for execution.  */
+  int length;
+
   /* If the breakpoint lives in memory and reading that memory would
      give back the breakpoint, instead of the original contents, then
      the original contents are cached here.  Only SHADOW_LEN bytes of
@@ -326,7 +330,8 @@ struct bp_location
   CORE_ADDR address;
 
   /* For hardware watchpoints, the size of the memory region being
-     watched.  */
+     watched.  For hardware ranged breakpoints, the size of the
+     breakpoint range.  */
   int length;
 
   /* Type of hardware watchpoint.  */
@@ -384,7 +389,8 @@ struct breakpoint_ops
 
   /* Return non-zero if the debugger should tell the user that this
      breakpoint was hit.  */
-  int (*breakpoint_hit) (struct breakpoint *);
+  int (*breakpoint_hit) (const struct bp_location *, struct address_space *,
+			 CORE_ADDR);
 
   /* Tell how many hardware resources (debug registers) are needed
      for this breakpoint.  If this function is not provided, then
@@ -399,6 +405,20 @@ struct breakpoint_ops
      breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".
+
+     In the example below, the "address range" line was printed
+     by print_one_detail_ranged_breakpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw breakpoint  keep y              in main at test-watch.c:70
+	     address range: [0x10000458, 0x100004c7]
+
+   */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it
      (roughly speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -489,6 +509,11 @@ struct breakpoint
 
     /* String we used to set the breakpoint (malloc'd).  */
     char *addr_string;
+
+    /* For a ranged breakpoint, the string we used to find
+       the end of the range (malloc'd).  */
+    char *addr_string_range_end;
+
     /* Architecture we used to set the breakpoint.  */
     struct gdbarch *gdbarch;
     /* Language we used to set the breakpoint.  */
diff --git a/gdb/defs.h b/gdb/defs.h
index 9409dde..9531c5a 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -532,6 +532,12 @@ extern const char *host_address_to_string (const void *addr);
    This is usually formatted similar to 0x%lx.  */
 extern const char *paddress (struct gdbarch *gdbarch, CORE_ADDR addr);
 
+/* Return a string representation in hexadecimal notation of ADDRESS,
+   which is suitable for printing.  */
+
+extern const char *print_core_address (struct gdbarch *gdbarch,
+				       CORE_ADDR address);
+
 /* %d for LONGEST */
 extern char *plongest (LONGEST l);
 /* %u for ULONGEST */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e023058..af9166f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18742,9 +18742,27 @@ region using one of the following commands (@pxref{Expressions}):
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+@cindex ranged breakpoint
+PowerPC embedded processors support hardware accelerated
+@dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
+the inferior whenever it executes an instruction at any address within
+the range it specifies.  To set a ranged breakpoint in @value{GDBN},
+use the @code{break-range} command.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex break-range
+@item break-range @var{start-location}, @var{end-location}
+Set a breakpoint for an address range.
+@var{start-location} and @var{end-location} can specify a function name,
+a line number, an offset of lines from the current line or from the start
+location, or an address of an instruction (see @ref{Specify Location},
+for a list of all the possible ways to specify a @var{location}.)
+The breakpoint will stop execution of the inferior whenever it
+executes an instruction at any address within the specified range,
+(including @var{start-location} and @var{end-location}.)
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 049cde8..f0c7f61 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1637,6 +1637,19 @@ booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
   hw_breaks[i].hw_break = NULL;
 }
 
+/* Return the number of registers needed for a ranged breakpoint.  */
+
+static int
+ppc_linux_ranged_break_num_registers (struct target_ops *target)
+{
+  return ((have_ptrace_booke_interface ()
+	   && booke_debug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
+	  2 : -1);
+}
+
+/* Insert the hardware breakpoint described by BP_TGT.  Returns 0 for
+   success, 1 if hardware breakpoints are not supported or -1 for failure.  */
+
 static int
 ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 				  struct bp_target_info *bp_tgt)
@@ -1650,12 +1663,24 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is
+	 within the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_insert_point (&p, TIDGET (ptid));
 
@@ -1675,12 +1700,24 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is within
+	 the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_remove_point (&p, TIDGET (ptid));
 
@@ -2392,6 +2429,7 @@ _initialize_ppc_linux_nat (void)
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/target.c b/gdb/target.c
index 45259fd..a032052 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -594,6 +594,7 @@ update_current_target (void)
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
+      /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
@@ -3491,6 +3492,21 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_ranged_break_num_registers (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_ranged_break_num_registers != NULL)
+      return t->to_ranged_break_num_registers (t);
+
+  return -1;
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
diff --git a/gdb/target.h b/gdb/target.h
index 237d1aa..f0b2e43 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -450,6 +450,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_ranged_break_num_registers) (struct target_ops *);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -1354,6 +1355,11 @@ extern char *target_thread_name (struct thread_info *);
 #define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_remove_hw_breakpoint) (gdbarch, bp_tgt)
 
+/* Return number of debug registers needed for a ranged breakpoint,
+   or -1 if ranged breakpoints are not supported.  */
+
+extern int target_ranged_break_num_registers (void);
+
 /* Return non-zero if target knows the data address which triggered this
    target_stopped_by_watchpoint, in such case place it to *ADDR_P.  Only the
    INFERIOR_PTID task is being queried.  */
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 2cd1a54..59aaa24 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -492,23 +492,8 @@ ui_out_field_core_addr (struct ui_out *uiout,
 			struct gdbarch *gdbarch,
 			CORE_ADDR address)
 {
-  /* Maximum size string returned by hex_string_custom is 50 chars.
-     This buffer must be bigger than that, for safety.  */
-  char addstr[64];
-  int addr_bit = gdbarch_addr_bit (gdbarch);
-
-  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
-    address &= ((CORE_ADDR) 1 << addr_bit) - 1;
-
-  /* FIXME: cagney/2002-05-03: Need local_address_string() function
-     that returns the language localized string formatted to a width
-     based on gdbarch_addr_bit.  */
-  if (addr_bit <= 32)
-    strcpy (addstr, hex_string_custom (address, 8));
-  else
-    strcpy (addstr, hex_string_custom (address, 16));
-
-  ui_out_field_string (uiout, fldname, addstr);
+  ui_out_field_string (uiout, fldname,
+		       print_core_address (gdbarch, address));
 }
 
 void
diff --git a/gdb/utils.c b/gdb/utils.c
index e688d19..496c9dc 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3224,6 +3224,25 @@ paddress (struct gdbarch *gdbarch, CORE_ADDR addr)
   return hex_string (addr);
 }
 
+/* This function is described in "defs.h".  */
+
+const char *
+print_core_address (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    address &= ((CORE_ADDR) 1 << addr_bit) - 1;
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+    return hex_string_custom (address, 8);
+  else
+    return hex_string_custom (address, 16);
+}
+
 static char *
 decimal2str (char *sign, ULONGEST addr, int width)
 {



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-28 16:50           ` Thiago Jung Bauermann
@ 2011-03-29 13:10             ` Ulrich Weigand
  2011-03-31 15:41               ` Thiago Jung Bauermann
  0 siblings, 1 reply; 22+ messages in thread
From: Ulrich Weigand @ 2011-03-29 13:10 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> In this patch I had to modify print_recreate_ranged_breakpoint to use
> addr_string_range_end since I don't use exp_string anymore. I could
> change print_mention_ranged_breakpoint to use it too, since it's
> formatted consistently. However, breakpoint.c:mention doesn't use
> b->addr_string and instead uses b->source_file and b->line_number, so
> I'm not sure if I should use b->addr_string_range_end. I left that out
> for now.

OK, that's fine with me.

> +  /* We call decode_line_n1 directly here instead of using

Typo: decode_line_1

> +     parse_breakpoint_sals because we need to specify the start location's
> +     symtab and line as the default symtab and line for the end of the
> +     range.  This makes it possible to have ranges like "foo.c:27, +14",
> +     where +14 means 14 lines from the start location.  */
> +  sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
> +                           &canonical_end, NULL);


> 2011-03-27  Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 	    Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> 
> 	Implement support for PowerPC BookE ranged breakpoints.
> 
> gdb/
> 	* NEWS: Mention support for ranged breakpoints on embedded PowerPC.
> 	* breakpoint.h (struct bp_target_info) <length>: New member
> 	variable.
> 	(struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
> 	instead of struct breakpoint as argument, and also add ASPACE
> 	and BP_ADDR arguments.  Update all callers.
> 	(struct breakpoint_ops) <print_one_detail>: New method.
> 	(struct breakpoint) <addr_string_range_end>: New member variable.
> 	* breakpoint.c (breakpoint_location_address_match): Add function
> 	prototype.
> 	(insert_bp_location): Set bl->target_info.length.
> 	(breakpoint_here_p): Call breakpoint_location_address_match.
> 	(moribund_breakpoint_here_p): Likewise.
> 	(regular_breakpoint_inserted_here_p): Likewise.
> 	(breakpoint_thread_match): Likewise.
> 	(bpstat_stop_status): Likewise.
> 	(bpstat_check_location): Move call to
> 	breakpoint_ops.breakpoint_hit to the top.
> 	(print_one_breakpoint_location): Call
> 	breakpoint_ops.print_one_detail if available.
> 	(breakpoint_address_match_range): New function.
> 	(breakpoint_location_address_match): Likewise.
> 	(breakpoint_locations_match): Compare the length field of the
> 	locations too.
> 	(hw_breakpoint_used_count): Count resources used by all locations
> 	in a breakpoint, and use breakpoint_ops.resources_needed if
> 	available.
> 	(breakpoint_hit_ranged_breakpoint): New function.
> 	(resources_needed_ranged_breakpoint): Likewise.
> 	(print_it_ranged_breakpoint): Likewise.
> 	(print_one_ranged_breakpoint): Likewise.
> 	(print_one_detail_ranged_breakpoint): Likewise.
> 	(print_mention_ranged_breakpoint): Likewise.
> 	(print_recreate_ranged_breakpoint): Likewise.
> 	(ranged_breakpoint_ops): New structure.
> 	(find_breakpoint_range_end): New function.
> 	(break_range_command): Likewise.
> 	(delete_breakpoint): Free addr_string_range_end.
> 	(update_breakpoint_locations): Add SALS_END argument.  Calculate
> 	breakpoint length if a non-zero SALS_END is given.  Call
> 	breakpoint_locations_match instead of breakpoint_address_match.
> 	(reset_breakpoint): Find SaL of the end of the range if B is a
> 	ranged breakpoint.
> 	(_initialize_breakpoint): Register break-range command.
> 	* defs.h (print_core_address): Add function prototype.
> 	* ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
> 	function.
> 	(ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
> 	(ppc_linux_remove_hw_breakpoint): Likewise.
> 	(_initialize_ppc_linux_nat): Initialize
> 	to_ranged_break_num_registers.
> 	* target.c (update_current_target): Add comment about
> 	to_ranged_break_num_registers.
> 	(target_ranged_break_num_registers): New function.
> 	* target.h (struct target_ops) <to_ranged_break_num_registers>:
> 	New method.
> 	(target_ranged_break_num_registers): Add function prototype.
> 	* ui-out.c (ui_out_field_core_addr): Move address-printing logic to ...
> 	* utils.c (print_core_address): ... here.
> 
> gdb/doc/
> 	* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.

Otherwise, this is OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-29 13:10             ` Ulrich Weigand
@ 2011-03-31 15:41               ` Thiago Jung Bauermann
  2011-03-31 16:04                 ` Thiago Jung Bauermann
  0 siblings, 1 reply; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-03-31 15:41 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Tue, 2011-03-29 at 14:23 +0200, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> > +  /* We call decode_line_n1 directly here instead of using
> 
> Typo: decode_line_1

Doh, forgot to fix that one in my commit. Will do in a moment.

> Otherwise, this is OK.

Awesome! Thank you very much for helping me with this patch!
I've just committed the patch below.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-03-31  Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

	Implement support for PowerPC BookE ranged breakpoints.

gdb/
	* NEWS: Mention support for ranged breakpoints on embedded PowerPC.
	* breakpoint.h (struct bp_target_info) <length>: New member
	variable.
	(struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
	instead of struct breakpoint as argument, and also add ASPACE
	and BP_ADDR arguments.  Update all callers.
	(struct breakpoint_ops) <print_one_detail>: New method.
	(struct breakpoint) <addr_string_range_end>: New member variable.
	* breakpoint.c (breakpoint_location_address_match): Add function
	prototype.
	(insert_bp_location): Set bl->target_info.length.
	(breakpoint_here_p): Call breakpoint_location_address_match.
	(moribund_breakpoint_here_p): Likewise.
	(regular_breakpoint_inserted_here_p): Likewise.
	(breakpoint_thread_match): Likewise.
	(bpstat_stop_status): Likewise.
	(bpstat_check_location): Move call to
	breakpoint_ops.breakpoint_hit to the top.
	(print_one_breakpoint_location): Call
	breakpoint_ops.print_one_detail if available.
	(breakpoint_address_match_range): New function.
	(breakpoint_location_address_match): Likewise.
	(breakpoint_locations_match): Compare the length field of the
	locations too.
	(hw_breakpoint_used_count): Count resources used by all locations
	in a breakpoint, and use breakpoint_ops.resources_needed if
	available.
	(breakpoint_hit_ranged_breakpoint): New function.
	(resources_needed_ranged_breakpoint): Likewise.
	(print_it_ranged_breakpoint): Likewise.
	(print_one_ranged_breakpoint): Likewise.
	(print_one_detail_ranged_breakpoint): Likewise.
	(print_mention_ranged_breakpoint): Likewise.
	(print_recreate_ranged_breakpoint): Likewise.
	(ranged_breakpoint_ops): New structure.
	(find_breakpoint_range_end): New function.
	(break_range_command): Likewise.
	(delete_breakpoint): Free addr_string_range_end.
	(update_breakpoint_locations): Add SALS_END argument.  Update
	all callers.  Calculate breakpoint length if a non-zero SALS_END
	is given.  Call breakpoint_locations_match instead of
	breakpoint_address_match.
	(reset_breakpoint): Find SaL of the end of the range if B is a
	ranged breakpoint.
	(_initialize_breakpoint): Register break-range command.
	* defs.h (print_core_address): Add function prototype.
	* ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
	function.
	(ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
	(ppc_linux_remove_hw_breakpoint): Likewise.
	(_initialize_ppc_linux_nat): Initialize
	to_ranged_break_num_registers.
	* target.c (update_current_target): Add comment about
	to_ranged_break_num_registers.
	(target_ranged_break_num_registers): New function.
	* target.h (struct target_ops) <to_ranged_break_num_registers>:
	New method.
	(target_ranged_break_num_registers): Add function prototype.
	* ui-out.c (ui_out_field_core_addr): Move address-printing logic to ...
	* utils.c (print_core_address): ... here.

gdb/doc/
	* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.


Index: gdb.git/gdb/NEWS
===================================================================
--- gdb.git.orig/gdb/NEWS	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/NEWS	2011-03-30 11:54:59.000000000 -0300
@@ -156,6 +156,12 @@
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
+  which stop execution of the inferior whenever it executes an instruction
+  at any address within the specified range.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
Index: gdb.git/gdb/ada-lang.c
===================================================================
--- gdb.git.orig/gdb/ada-lang.c	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/ada-lang.c	2011-03-30 11:54:59.000000000 -0300
@@ -10925,6 +10925,7 @@ static struct breakpoint_ops catch_excep
   NULL, /* resources_needed */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10964,6 +10965,7 @@ static struct breakpoint_ops catch_excep
   NULL, /* resources_needed */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -11001,6 +11003,7 @@ static struct breakpoint_ops catch_asser
   NULL, /* resources_needed */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
Index: gdb.git/gdb/breakpoint.c
===================================================================
--- gdb.git.orig/gdb/breakpoint.c	2011-03-30 11:54:59.000000000 -0300
+++ gdb.git/gdb/breakpoint.c	2011-03-30 11:54:59.000000000 -0300
@@ -131,6 +131,10 @@ static int breakpoint_address_match (str
 static int watchpoint_locations_match (struct bp_location *loc1,
 				       struct bp_location *loc2);
 
+static int breakpoint_location_address_match (struct bp_location *bl,
+					      struct address_space *aspace,
+					      CORE_ADDR addr);
+
 static void breakpoints_info (char *, int);
 
 static void watchpoints_info (char *, int);
@@ -1537,6 +1541,7 @@ insert_bp_location (struct bp_location *
   memset (&bl->target_info, 0, sizeof (bl->target_info));
   bl->target_info.placed_address = bl->address;
   bl->target_info.placed_address_space = bl->pspace->aspace;
+  bl->target_info.length = bl->length;
 
   if (bl->loc_type == bp_loc_software_breakpoint
       || bl->loc_type == bp_loc_hardware_breakpoint)
@@ -2799,11 +2804,10 @@ breakpoint_here_p (struct address_space
 	  && bl->loc_type != bp_loc_hardware_breakpoint)
 	continue;
 
-      /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL.  */
+      /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL.  */
       if ((breakpoint_enabled (bl->owner)
 	   || bl->owner->enable_state == bp_permanent)
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2828,8 +2832,7 @@ moribund_breakpoint_here_p (struct addre
   int ix;
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
-    if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				  aspace,  pc))
+    if (breakpoint_location_address_match (loc, aspace, pc))
       return 1;
 
   return 0;
@@ -2853,8 +2856,7 @@ regular_breakpoint_inserted_here_p (stru
 	continue;
 
       if (bl->inserted
-	  && breakpoint_address_match (bl->pspace->aspace, bl->address,
-				       aspace, pc))
+	  && breakpoint_location_address_match (bl, aspace, pc))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bl->section)
@@ -2971,8 +2973,7 @@ breakpoint_thread_match (struct address_
 	  && bl->owner->enable_state != bp_permanent)
 	continue;
 
-      if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
-				     aspace, pc))
+      if (!breakpoint_location_address_match (bl, aspace, pc))
 	continue;
 
       if (bl->owner->thread != -1)
@@ -3860,6 +3861,9 @@ bpstat_check_location (const struct bp_l
   /* BL is from existing struct breakpoint.  */
   gdb_assert (b != NULL);
 
+  if (b->ops && b->ops->breakpoint_hit)
+    return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+
   /* By definition, the inferior does not report stops at
      tracepoints.  */
   if (is_tracepoint (b))
@@ -3888,7 +3892,7 @@ bpstat_check_location (const struct bp_l
   if (is_hardware_watchpoint (b)
       && b->watchpoint_triggered == watch_triggered_no)
     return 0;
-  
+
   if (b->type == bp_hardware_breakpoint)
     {
       if (bl->address != bp_addr)
@@ -3899,13 +3903,6 @@ bpstat_check_location (const struct bp_l
 	return 0;
     }
 
-  if (b->type == bp_catchpoint)
-    {
-      gdb_assert (b->ops != NULL && b->ops->breakpoint_hit != NULL);
-      if (!b->ops->breakpoint_hit (b))
-        return 0;
-    }
-     
   return 1;
 }
 
@@ -4265,8 +4262,7 @@ bpstat_stop_status (struct address_space
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
     {
-      if (breakpoint_address_match (loc->pspace->aspace, loc->address,
-				    aspace, bp_addr))
+      if (breakpoint_location_address_match (loc, aspace, bp_addr))
 	{
 	  bs = bpstat_alloc (loc, &bs_link);
 	  /* For hits of moribund locations, we should just proceed.  */
@@ -4952,9 +4948,12 @@ print_one_breakpoint_location (struct br
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5537,6 +5536,39 @@ breakpoint_address_match (struct address
 	  && addr1 == addr2);
 }
 
+/* Returns true if {ASPACE2,ADDR2} falls within the range determined by
+   {ASPACE1,ADDR1,LEN1}.  In most targets, this can only be true if ASPACE1
+   matches ASPACE2.  On targets that have global breakpoints, the address
+   space doesn't really matter.  */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+				int len1, struct address_space *aspace2,
+				CORE_ADDR addr2)
+{
+  return ((gdbarch_has_global_breakpoints (target_gdbarch)
+	   || aspace1 == aspace2)
+	  && addr2 >= addr1 && addr2 < addr1 + len1);
+}
+
+/* Returns true if {ASPACE,ADDR} matches the breakpoint BL.  BL may be
+   a ranged breakpoint.  In most targets, a match happens only if ASPACE
+   matches the breakpoint's address space.  On targets that have global
+   breakpoints, the address space doesn't really matter.  */
+
+static int
+breakpoint_location_address_match (struct bp_location *bl,
+				   struct address_space *aspace,
+				   CORE_ADDR addr)
+{
+  return (breakpoint_address_match (bl->pspace->aspace, bl->address,
+				    aspace, addr)
+	  || (bl->length
+	      && breakpoint_address_match_range (bl->pspace->aspace,
+						 bl->address, bl->length,
+						 aspace, addr)));
+}
+
 /* Assuming LOC1 and LOC2's types' have meaningful target addresses
    (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
    represent the same location.  */
@@ -5559,8 +5591,10 @@ breakpoint_locations_match (struct bp_lo
   else if (hw_point1)
     return watchpoint_locations_match (loc1, loc2);
   else
-    return breakpoint_address_match (loc1->pspace->aspace, loc1->address,
-				     loc2->pspace->aspace, loc2->address);
+    /* We compare bp_location.length in order to cover ranged breakpoints.  */
+    return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
+				     loc2->pspace->aspace, loc2->address)
+	    && loc1->length == loc2->length);
 }
 
 static void
@@ -6201,9 +6235,10 @@ remove_catch_fork (struct bp_location *b
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_fork (struct breakpoint *b)
+breakpoint_hit_catch_fork (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_forked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for fork
@@ -6272,6 +6307,7 @@ static struct breakpoint_ops catch_fork_
   NULL, /* resources_needed */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -6298,9 +6334,10 @@ remove_catch_vfork (struct bp_location *
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_vfork (struct breakpoint *b)
+breakpoint_hit_catch_vfork (const struct bp_location *bl,
+			    struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_vforked (inferior_ptid, &b->forked_inferior_pid);
+  return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
 }
 
 /* Implement the "print_it" breakpoint_ops method for vfork
@@ -6368,6 +6405,7 @@ static struct breakpoint_ops catch_vfork
   NULL, /* resources_needed */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6457,12 +6495,14 @@ remove_catch_syscall (struct bp_location
    catchpoints.  */
 
 static int
-breakpoint_hit_catch_syscall (struct breakpoint *b)
+breakpoint_hit_catch_syscall (const struct bp_location *bl,
+			      struct address_space *aspace, CORE_ADDR bp_addr)
 {
   /* We must check if we are catching specific syscalls in this
      breakpoint.  If we are, then we must guarantee that the called
      syscall is the same syscall we are catching.  */
   int syscall_number = 0;
+  const struct breakpoint *b = bl->owner;
 
   if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
     return 0;
@@ -6531,7 +6571,7 @@ print_it_catch_syscall (struct breakpoin
 
 static void
 print_one_catch_syscall (struct breakpoint *b,
-                         struct bp_location **last_loc)
+			 struct bp_location **last_loc)
 {
   struct value_print_options opts;
 
@@ -6652,6 +6692,7 @@ static struct breakpoint_ops catch_sysca
   NULL, /* resources_needed */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6747,9 +6788,10 @@ remove_catch_exec (struct bp_location *b
 }
 
 static int
-breakpoint_hit_catch_exec (struct breakpoint *b)
+breakpoint_hit_catch_exec (const struct bp_location *bl,
+			   struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_execd (inferior_ptid, &b->exec_pathname);
+  return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
 }
 
 static enum print_stop_action
@@ -6806,6 +6848,7 @@ static struct breakpoint_ops catch_exec_
   NULL, /* resources_needed */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6829,13 +6872,22 @@ create_syscall_event_catchpoint (int tem
 static int
 hw_breakpoint_used_count (void)
 {
-  struct breakpoint *b;
   int i = 0;
+  struct breakpoint *b;
+  struct bp_location *bl;
 
   ALL_BREAKPOINTS (b)
   {
     if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
-      i++;
+      for (bl = b->loc; bl; bl = bl->next)
+	{
+	  /* Special types of hardware breakpoints may use more than
+	     one register.  */
+	  if (b->ops && b->ops->resources_needed)
+	    i += b->ops->resources_needed (bl);
+	  else
+	    i++;
+	}
   }
 
   return i;
@@ -8303,6 +8355,309 @@ stopat_command (char *arg, int from_tty)
     break_command_1 (arg, 0, from_tty);
 }
 
+/* Implement the "breakpoint_hit" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+				  struct address_space *aspace,
+				  CORE_ADDR bp_addr)
+{
+  return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+					 bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+  return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  annotate_breakpoint (b->number);
+  if (b->disposition == disp_del)
+    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+  else
+    ui_out_text (uiout, "\nRanged breakpoint ");
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+    }
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
+
+  return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+			     struct bp_location **last_loc)
+{
+  struct bp_location *bl = b->loc;
+  struct value_print_options opts;
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  get_user_print_options (&opts);
+
+  if (opts.addressprint)
+    /* We don't print the address range here, it will be printed later
+       by print_one_detail_ranged_breakpoint.  */
+    ui_out_field_skip (uiout, "addr");
+  annotate_field (5);
+  print_breakpoint_location (b, bl);
+  *last_loc = bl;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  CORE_ADDR address_start, address_end;
+  struct bp_location *bl = b->loc;
+  struct ui_stream *stb = ui_out_stream_new (uiout);
+  struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
+
+  gdb_assert (bl);
+
+  address_start = bl->address;
+  address_end = address_start + bl->length - 1;
+
+  ui_out_text (uiout, "\taddress range: ");
+  fprintf_unfiltered (stb->stream, "[%s, %s]",
+		      print_core_address (bl->gdbarch, address_start),
+		      print_core_address (bl->gdbarch, address_end));
+  ui_out_field_stream (uiout, "addr", stb);
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (cleanup);
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (bl);
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  if (ui_out_is_mi_like_p (uiout))
+    return;
+
+  printf_filtered (_("Hardware assisted ranged breakpoint %d from %s to %s."),
+		   b->number, paddress (bl->gdbarch, bl->address),
+		   paddress (bl->gdbarch, bl->address + bl->length - 1));
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
+		      b->addr_string_range_end);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints.  */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+  NULL, /* insert */
+  NULL, /* remove */
+  breakpoint_hit_ranged_breakpoint,
+  resources_needed_ranged_breakpoint,
+  print_it_ranged_breakpoint,
+  print_one_ranged_breakpoint,
+  print_one_detail_ranged_breakpoint,
+  print_mention_ranged_breakpoint,
+  print_recreate_ranged_breakpoint
+};
+
+/* Find the address where the end of the breakpoint range should be
+   placed, given the SAL of the end of the range.  This is so that if
+   the user provides a line number, the end of the range is set to the
+   last instruction of the given line.  */
+
+static CORE_ADDR
+find_breakpoint_range_end (struct symtab_and_line sal)
+{
+  CORE_ADDR end;
+
+  /* If the user provided a PC value, use it.  Otherwise,
+     find the address of the end of the given location.  */
+  if (sal.explicit_pc)
+    end = sal.pc;
+  else
+    {
+      int ret;
+      CORE_ADDR start;
+
+      ret = find_line_pc_range (sal, &start, &end);
+      if (!ret)
+	error (_("Could not find location of the end of the range."));
+
+      /* find_line_pc_range returns the start of the next line.  */
+      end--;
+    }
+
+  return end;
+}
+
+/* Implement the "break-range" CLI command.  */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+  char *arg_start, *addr_string_start, *addr_string_end;
+  struct linespec_result canonical_start, canonical_end;
+  int bp_count, can_use_bp, length;
+  CORE_ADDR end;
+  struct breakpoint *b;
+  struct symtab_and_line sal_start, sal_end;
+  struct symtabs_and_lines sals_start, sals_end;
+  struct cleanup *cleanup_bkpt;
+
+  /* We don't support software ranged breakpoints.  */
+  if (target_ranged_break_num_registers () < 0)
+    error (_("This target does not support hardware ranged breakpoints."));
+
+  bp_count = hw_breakpoint_used_count ();
+  bp_count += target_ranged_break_num_registers ();
+  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+						   bp_count, 0);
+  if (can_use_bp < 0)
+    error (_("Hardware breakpoints used exceeds limit."));
+
+  if (arg == NULL || arg[0] == '\0')
+    error(_("No address range specified."));
+
+  sals_start.sals = NULL;
+  sals_start.nelts = 0;
+  init_linespec_result (&canonical_start);
+
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  parse_breakpoint_sals (&arg, &sals_start, &canonical_start, NULL);
+
+  sal_start = sals_start.sals[0];
+  addr_string_start = canonical_start.canonical[0];
+  cleanup_bkpt = make_cleanup (xfree, addr_string_start);
+  xfree (sals_start.sals);
+  xfree (canonical_start.canonical);
+
+  if (arg[0] != ',')
+    error (_("Too few arguments."));
+  else if (sals_start.nelts == 0)
+    error (_("Could not find location of the beginning of the range."));
+  else if (sals_start.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  resolve_sal_pc (&sal_start);
+
+  arg++;	/* Skip the comma.  */
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  /* Parse the end location.  */
+
+  sals_end.sals = NULL;
+  sals_end.nelts = 0;
+  init_linespec_result (&canonical_end);
+  arg_start = arg;
+
+  /* We call decode_line_n1 directly here instead of using
+     parse_breakpoint_sals because we need to specify the start location's
+     symtab and line as the default symtab and line for the end of the
+     range.  This makes it possible to have ranges like "foo.c:27, +14",
+     where +14 means 14 lines from the start location.  */
+  sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
+			    &canonical_end, NULL);
+
+  /* canonical_end can be NULL if it was of the form "*0xdeadbeef".  */
+  if (canonical_end.canonical == NULL)
+    canonical_end.canonical = xcalloc (1, sizeof (char **));
+  /* Add the string if not present.  */
+  if (arg_start != arg && canonical_end.canonical[0] == NULL)
+    canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
+
+  sal_end = sals_end.sals[0];
+  addr_string_end = canonical_end.canonical[0];
+  make_cleanup (xfree, addr_string_end);
+  xfree (sals_end.sals);
+  xfree (canonical_end.canonical);
+
+  if (sals_end.nelts == 0)
+    error (_("Could not find location of the end of the range."));
+  else if (sals_end.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  resolve_sal_pc (&sal_end);
+
+  end = find_breakpoint_range_end (sal_end);
+  if (sal_start.pc > end)
+    error (_("Invalid address range, end preceeds start."));
+
+  length = end - sal_start.pc + 1;
+  if (length < 0)
+    /* Length overflowed.  */
+    error (_("Address range too large."));
+  else if (length == 1)
+    {
+      /* This range is simple enough to be handled by
+	 the `hbreak' command.  */
+      hbreak_command (addr_string_start, 1);
+
+      do_cleanups (cleanup_bkpt);
+
+      return;
+    }
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (get_current_arch (), sal_start,
+			  bp_hardware_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->disposition = disp_donttouch;
+  b->addr_string = addr_string_start;
+  b->addr_string_range_end = addr_string_end;
+  b->ops = &ranged_breakpoint_ops;
+  b->loc->length = length;
+
+  discard_cleanups (cleanup_bkpt);
+
+  mention (b);
+  update_global_location_list (1);
+}
+
 /*  Return non-zero if EXP is verified as constant.  Returned zero
     means EXP is variable.  Also the constant detection may fail for
     some constant expressions and in such case still falsely return
@@ -8455,6 +8810,7 @@ static struct breakpoint_ops watchpoint_
   resources_needed_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
@@ -9233,6 +9589,7 @@ static struct breakpoint_ops gnu_v3_exce
   NULL, /* resources_needed */
   print_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -10179,6 +10536,7 @@ delete_breakpoint (struct breakpoint *bp
   xfree (bpt->cond_string);
   xfree (bpt->cond_exp);
   xfree (bpt->addr_string);
+  xfree (bpt->addr_string_range_end);
   xfree (bpt->exp);
   xfree (bpt->exp_string);
   xfree (bpt->exp_string_reparse);
@@ -10473,14 +10831,21 @@ update_static_tracepoint (struct breakpo
   return sal;
 }
 
+/* Create new breakpoint locations for B (a hardware or software breakpoint)
+   based on SALS and SALS_END.  If SALS_END.NELTS is not zero, then B is
+   a ranged breakpoint.  */
+
 void
 update_breakpoint_locations (struct breakpoint *b,
-			     struct symtabs_and_lines sals)
+			     struct symtabs_and_lines sals,
+			     struct symtabs_and_lines sals_end)
 {
   int i;
-  char *s;
   struct bp_location *existing_locations = b->loc;
 
+  /* Ranged breakpoints have only one start location and one end location.  */
+  gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+
   /* If there's no new locations, and all existing locations are
      pending, don't do anything.  This optimizes the common case where
      all locations are in the same shared library, that was unloaded.
@@ -10501,6 +10866,7 @@ update_breakpoint_locations (struct brea
 	 old symtab.  */
       if (b->cond_string != NULL)
 	{
+	  char *s;
 	  struct gdb_exception e;
 
 	  s = b->cond_string;
@@ -10527,6 +10893,13 @@ update_breakpoint_locations (struct brea
 
       if (b->line_number == 0)
 	b->line_number = sals.sals[i].line;
+
+      if (sals_end.nelts)
+	{
+	  CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
+
+	  new_loc->length = end - sals.sals[0].pc + 1;
+	}
     }
 
   /* Update locations of permanent breakpoints.  */
@@ -10552,8 +10925,7 @@ update_breakpoint_locations (struct brea
 	    if (have_ambiguous_names)
 	      {
 		for (; l; l = l->next)
-		  if (breakpoint_address_match (e->pspace->aspace, e->address,
-						l->pspace->aspace, l->address))
+		  if (breakpoint_locations_match (e, l))
 		    {
 		      l->enabled = 0;
 		      break;
@@ -10673,8 +11045,9 @@ static void
 re_set_breakpoint (struct breakpoint *b)
 {
   int found;
-  struct symtabs_and_lines sals;
+  struct symtabs_and_lines sals, sals_end;
   struct symtabs_and_lines expanded = {0};
+  struct symtabs_and_lines expanded_end = {0};
   struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
 
   input_radix = b->input_radix;
@@ -10689,7 +11062,17 @@ re_set_breakpoint (struct breakpoint *b)
       expanded = expand_line_sal_maybe (sals.sals[0]);
     }
 
-  update_breakpoint_locations (b, expanded);
+  if (b->addr_string_range_end)
+    {
+      sals_end = addr_string_to_sals (b, b->addr_string_range_end, &found);
+      if (found)
+	{
+	  make_cleanup (xfree, sals_end.sals);
+	  expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+	}
+    }
+
+  update_breakpoint_locations (b, expanded, expanded_end);
   do_cleanups (cleanups);
 }
 
@@ -12733,7 +13116,23 @@ inferior in all-stop mode, gdb behaves a
 			   &show_always_inserted_mode,
 			   &breakpoint_set_cmdlist,
 			   &breakpoint_show_cmdlist);
-  
+
+  add_com ("break-range", class_breakpoint, break_range_command, _("\
+Set a breakpoint for an address range.\n\
+break-range START-LOCATION, END-LOCATION\n\
+where START-LOCATION and END-LOCATION can be one of the following:\n\
+  LINENUM, for that line in the current file,\n\
+  FILE:LINENUM, for that line in that file,\n\
+  +OFFSET, for that number of lines after the current line\n\
+           or the start of the range\n\
+  FUNCTION, for the first line in that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, for the instruction at that address.\n\
+\n\
+The breakpoint will stop execution of the inferior whenever it executes\n\
+an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
+range (including START-LOCATION and END-LOCATION)."));
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
Index: gdb.git/gdb/breakpoint.h
===================================================================
--- gdb.git.orig/gdb/breakpoint.h	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/breakpoint.h	2011-03-30 15:55:53.000000000 -0300
@@ -231,6 +231,10 @@ struct bp_target_info
      is used to determine the type of breakpoint to insert.  */
   CORE_ADDR placed_address;
 
+  /* If this is a ranged breakpoint, then this field contains the
+     length of the range that will be watched for execution.  */
+  int length;
+
   /* If the breakpoint lives in memory and reading that memory would
      give back the breakpoint, instead of the original contents, then
      the original contents are cached here.  Only SHADOW_LEN bytes of
@@ -339,7 +343,8 @@ struct bp_location
   CORE_ADDR address;
 
   /* For hardware watchpoints, the size of the memory region being
-     watched.  */
+     watched.  For hardware ranged breakpoints, the size of the
+     breakpoint range.  */
   int length;
 
   /* Type of hardware watchpoint.  */
@@ -397,7 +402,8 @@ struct breakpoint_ops
 
   /* Return non-zero if the debugger should tell the user that this
      breakpoint was hit.  */
-  int (*breakpoint_hit) (struct breakpoint *);
+  int (*breakpoint_hit) (const struct bp_location *, struct address_space *,
+			 CORE_ADDR);
 
   /* Tell how many hardware resources (debug registers) are needed
      for this breakpoint.  If this function is not provided, then
@@ -412,6 +418,20 @@ struct breakpoint_ops
      breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".
+
+     In the example below, the "address range" line was printed
+     by print_one_detail_ranged_breakpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw breakpoint  keep y              in main at test-watch.c:70
+	     address range: [0x10000458, 0x100004c7]
+
+   */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it
      (roughly speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -502,6 +522,11 @@ struct breakpoint
 
     /* String we used to set the breakpoint (malloc'd).  */
     char *addr_string;
+
+    /* For a ranged breakpoint, the string we used to find
+       the end of the range (malloc'd).  */
+    char *addr_string_range_end;
+
     /* Architecture we used to set the breakpoint.  */
     struct gdbarch *gdbarch;
     /* Language we used to set the breakpoint.  */
@@ -904,7 +929,8 @@ extern int breakpoint_thread_match (stru
 extern void until_break_command (char *, int, int);
 
 extern void update_breakpoint_locations (struct breakpoint *b,
-					 struct symtabs_and_lines sals);
+					 struct symtabs_and_lines sals,
+					 struct symtabs_and_lines sals_end);
 
 extern void breakpoint_re_set (void);
 
Index: gdb.git/gdb/defs.h
===================================================================
--- gdb.git.orig/gdb/defs.h	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/defs.h	2011-03-30 11:54:59.000000000 -0300
@@ -532,6 +532,12 @@ extern const char *host_address_to_strin
    This is usually formatted similar to 0x%lx.  */
 extern const char *paddress (struct gdbarch *gdbarch, CORE_ADDR addr);
 
+/* Return a string representation in hexadecimal notation of ADDRESS,
+   which is suitable for printing.  */
+
+extern const char *print_core_address (struct gdbarch *gdbarch,
+				       CORE_ADDR address);
+
 /* %d for LONGEST */
 extern char *plongest (LONGEST l);
 /* %u for ULONGEST */
Index: gdb.git/gdb/doc/gdb.texinfo
===================================================================
--- gdb.git.orig/gdb/doc/gdb.texinfo	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/doc/gdb.texinfo	2011-03-30 11:54:59.000000000 -0300
@@ -18742,9 +18742,27 @@ region using one of the following comman
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+@cindex ranged breakpoint
+PowerPC embedded processors support hardware accelerated
+@dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
+the inferior whenever it executes an instruction at any address within
+the range it specifies.  To set a ranged breakpoint in @value{GDBN},
+use the @code{break-range} command.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex break-range
+@item break-range @var{start-location}, @var{end-location}
+Set a breakpoint for an address range.
+@var{start-location} and @var{end-location} can specify a function name,
+a line number, an offset of lines from the current line or from the start
+location, or an address of an instruction (see @ref{Specify Location},
+for a list of all the possible ways to specify a @var{location}.)
+The breakpoint will stop execution of the inferior whenever it
+executes an instruction at any address within the specified range,
+(including @var{start-location} and @var{end-location}.)
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
Index: gdb.git/gdb/ppc-linux-nat.c
===================================================================
--- gdb.git.orig/gdb/ppc-linux-nat.c	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/ppc-linux-nat.c	2011-03-30 11:54:59.000000000 -0300
@@ -1637,6 +1637,19 @@ booke_remove_point (struct ppc_hw_breakp
   hw_breaks[i].hw_break = NULL;
 }
 
+/* Return the number of registers needed for a ranged breakpoint.  */
+
+static int
+ppc_linux_ranged_break_num_registers (struct target_ops *target)
+{
+  return ((have_ptrace_booke_interface ()
+	   && booke_debug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
+	  2 : -1);
+}
+
+/* Insert the hardware breakpoint described by BP_TGT.  Returns 0 for
+   success, 1 if hardware breakpoints are not supported or -1 for failure.  */
+
 static int
 ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 				  struct bp_target_info *bp_tgt)
@@ -1650,12 +1663,24 @@ ppc_linux_insert_hw_breakpoint (struct g
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is
+	 within the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_insert_point (&p, TIDGET (ptid));
 
@@ -1675,12 +1700,24 @@ ppc_linux_remove_hw_breakpoint (struct g
 
   p.version = PPC_DEBUG_CURRENT_VERSION;
   p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
   p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
   p.addr = (uint64_t) bp_tgt->placed_address;
-  p.addr2 = 0;
   p.condition_value = 0;
 
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is within
+	 the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
   ALL_LWPS (lp, ptid)
     booke_remove_point (&p, TIDGET (ptid));
 
@@ -2392,6 +2429,7 @@ _initialize_ppc_linux_nat (void)
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
Index: gdb.git/gdb/target.c
===================================================================
--- gdb.git.orig/gdb/target.c	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/target.c	2011-03-30 11:54:59.000000000 -0300
@@ -594,6 +594,7 @@ update_current_target (void)
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
+      /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
@@ -3491,6 +3492,21 @@ target_verify_memory (const gdb_byte *da
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_ranged_break_num_registers (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_ranged_break_num_registers != NULL)
+      return t->to_ranged_break_num_registers (t);
+
+  return -1;
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
Index: gdb.git/gdb/target.h
===================================================================
--- gdb.git.orig/gdb/target.h	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/target.h	2011-03-30 11:54:59.000000000 -0300
@@ -450,6 +450,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_ranged_break_num_registers) (struct target_ops *);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -1354,6 +1355,11 @@ extern char *target_thread_name (struct
 #define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_remove_hw_breakpoint) (gdbarch, bp_tgt)
 
+/* Return number of debug registers needed for a ranged breakpoint,
+   or -1 if ranged breakpoints are not supported.  */
+
+extern int target_ranged_break_num_registers (void);
+
 /* Return non-zero if target knows the data address which triggered this
    target_stopped_by_watchpoint, in such case place it to *ADDR_P.  Only the
    INFERIOR_PTID task is being queried.  */
Index: gdb.git/gdb/ui-out.c
===================================================================
--- gdb.git.orig/gdb/ui-out.c	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/ui-out.c	2011-03-30 11:54:59.000000000 -0300
@@ -492,23 +492,8 @@ ui_out_field_core_addr (struct ui_out *u
 			struct gdbarch *gdbarch,
 			CORE_ADDR address)
 {
-  /* Maximum size string returned by hex_string_custom is 50 chars.
-     This buffer must be bigger than that, for safety.  */
-  char addstr[64];
-  int addr_bit = gdbarch_addr_bit (gdbarch);
-
-  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
-    address &= ((CORE_ADDR) 1 << addr_bit) - 1;
-
-  /* FIXME: cagney/2002-05-03: Need local_address_string() function
-     that returns the language localized string formatted to a width
-     based on gdbarch_addr_bit.  */
-  if (addr_bit <= 32)
-    strcpy (addstr, hex_string_custom (address, 8));
-  else
-    strcpy (addstr, hex_string_custom (address, 16));
-
-  ui_out_field_string (uiout, fldname, addstr);
+  ui_out_field_string (uiout, fldname,
+		       print_core_address (gdbarch, address));
 }
 
 void
Index: gdb.git/gdb/utils.c
===================================================================
--- gdb.git.orig/gdb/utils.c	2011-03-30 11:41:55.000000000 -0300
+++ gdb.git/gdb/utils.c	2011-03-30 11:54:59.000000000 -0300
@@ -3224,6 +3224,25 @@ paddress (struct gdbarch *gdbarch, CORE_
   return hex_string (addr);
 }
 
+/* This function is described in "defs.h".  */
+
+const char *
+print_core_address (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    address &= ((CORE_ADDR) 1 << addr_bit) - 1;
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+    return hex_string_custom (address, 8);
+  else
+    return hex_string_custom (address, 16);
+}
+
 static char *
 decimal2str (char *sign, ULONGEST addr, int width)
 {
Index: gdb.git/gdb/elfread.c
===================================================================
--- gdb.git.orig/gdb/elfread.c	2011-03-30 16:07:57.000000000 -0300
+++ gdb.git/gdb/elfread.c	2011-03-30 16:08:01.000000000 -0300
@@ -1011,7 +1011,7 @@ elf_gnu_ifunc_resolver_return_stop (stru
   struct value *value;
   CORE_ADDR resolved_address, resolved_pc;
   struct symtab_and_line sal;
-  struct symtabs_and_lines sals;
+  struct symtabs_and_lines sals, sals_end;
 
   gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
 
@@ -1050,9 +1050,10 @@ elf_gnu_ifunc_resolver_return_stop (stru
   sal = find_pc_line (resolved_pc, 0);
   sals.nelts = 1;
   sals.sals = &sal;
+  sals_end.nelts = 0;
 
   b->type = bp_breakpoint;
-  update_breakpoint_locations (b, sals);
+  update_breakpoint_locations (b, sals, sals_end);
 }
 
 struct build_id


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE ranged breakpoints
  2011-03-31 15:41               ` Thiago Jung Bauermann
@ 2011-03-31 16:04                 ` Thiago Jung Bauermann
  0 siblings, 0 replies; 22+ messages in thread
From: Thiago Jung Bauermann @ 2011-03-31 16:04 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Thu, 2011-03-31 at 11:46 -0300, Thiago Jung Bauermann wrote:
> On Tue, 2011-03-29 at 14:23 +0200, Ulrich Weigand wrote:
> > Thiago Jung Bauermann wrote:
> > > +  /* We call decode_line_n1 directly here instead of using
> > 
> > Typo: decode_line_1
> 
> Doh, forgot to fix that one in my commit. Will do in a moment.

Committed the following.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-03-31  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (break_range_command): Fix typo in comment.

Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.560
diff -u -r1.560 breakpoint.c
--- breakpoint.c	31 Mar 2011 14:32:48 -0000	1.560
+++ breakpoint.c	31 Mar 2011 15:00:17 -0000
@@ -8594,7 +8594,7 @@
   init_linespec_result (&canonical_end);
   arg_start = arg;
 
-  /* We call decode_line_n1 directly here instead of using
+  /* We call decode_line_1 directly here instead of using
      parse_breakpoint_sals because we need to specify the start location's
      symtab and line as the default symtab and line for the end of the
      range.  This makes it possible to have ranges like "foo.c:27, +14",



^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2011-03-31 15:03 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-28  1:54 [RFA] Implement support for PowerPC BookE ranged breakpoints Thiago Jung Bauermann
2011-01-28  9:39 ` Eli Zaretskii
2011-01-31 19:07   ` Thiago Jung Bauermann
2011-01-31 20:39     ` Eli Zaretskii
2011-02-17 15:49 ` Ulrich Weigand
2011-02-23 20:50   ` Thiago Jung Bauermann
2011-02-24 20:45     ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Ulrich Weigand
2011-02-25 14:46       ` Pedro Alves
2011-02-28 15:33         ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoin Ulrich Weigand
2011-02-28 16:34           ` [commit] Remove unused parameter (Re: [rfc] More intelligent indenting of multi-line table entries) Ulrich Weigand
2011-02-25 15:33       ` [rfc] More intelligent indenting of multi-line table entries (Re: [RFA] Implement support for PowerPC BookE ranged breakpoints) Thiago Jung Bauermann
2011-02-28 17:08     ` [RFA] Implement support for PowerPC BookE ranged breakpoints Ulrich Weigand
2011-03-12  2:03       ` Thiago Jung Bauermann
2011-03-12 16:44         ` Thiago Jung Bauermann
2011-03-14 20:50           ` Ulrich Weigand
2011-03-16  6:07             ` Thiago Jung Bauermann
2011-03-16 18:00               ` Ulrich Weigand
2011-03-14 21:02         ` Ulrich Weigand
2011-03-28 16:50           ` Thiago Jung Bauermann
2011-03-29 13:10             ` Ulrich Weigand
2011-03-31 15:41               ` Thiago Jung Bauermann
2011-03-31 16:04                 ` Thiago Jung Bauermann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).