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]

Re: [RFA] Implement support for PowerPC BookE ranged breakpoints


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




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