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


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

[RFA] Implement support for PowerPC BookE ranged breakpoints


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);
 



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