2011-03-31 Thiago Jung Bauermann <bauerman@br.ibm.com>
authorThiago Jung Bauermann <bauerman@br.ibm.com>
Thu, 31 Mar 2011 14:32:49 +0000 (14:32 +0000)
committerThiago Jung Bauermann <bauerman@br.ibm.com>
Thu, 31 Mar 2011 14:32:49 +0000 (14:32 +0000)
    Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

Implement support for PowerPC BookE ranged breakpoints.

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

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

14 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/ada-lang.c
gdb/breakpoint.c
gdb/breakpoint.h
gdb/defs.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/elfread.c
gdb/ppc-linux-nat.c
gdb/target.c
gdb/target.h
gdb/ui-out.c
gdb/utils.c

index 3f49dcc028cadcf436e8d06b98909c6c3752cef4..4da68a0fcefcc113b9a1a5ab026bc25e5aa9a710 100644 (file)
@@ -1,3 +1,68 @@
+2011-03-31  Thiago Jung Bauermann  <bauerman@br.ibm.com>
+           Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
+
+       Implement support for PowerPC BookE ranged breakpoints.
+       * NEWS: Mention support for ranged breakpoints on embedded PowerPC.
+       * breakpoint.h (struct bp_target_info) <length>: New member
+       variable.
+       (struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
+       instead of struct breakpoint as argument, and also add ASPACE
+       and BP_ADDR arguments.  Update all callers.
+       (struct breakpoint_ops) <print_one_detail>: New method.
+       (struct breakpoint) <addr_string_range_end>: New member variable.
+       * breakpoint.c (breakpoint_location_address_match): Add function
+       prototype.
+       (insert_bp_location): Set bl->target_info.length.
+       (breakpoint_here_p): Call breakpoint_location_address_match.
+       (moribund_breakpoint_here_p): Likewise.
+       (regular_breakpoint_inserted_here_p): Likewise.
+       (breakpoint_thread_match): Likewise.
+       (bpstat_stop_status): Likewise.
+       (bpstat_check_location): Move call to
+       breakpoint_ops.breakpoint_hit to the top.
+       (print_one_breakpoint_location): Call
+       breakpoint_ops.print_one_detail if available.
+       (breakpoint_address_match_range): New function.
+       (breakpoint_location_address_match): Likewise.
+       (breakpoint_locations_match): Compare the length field of the
+       locations too.
+       (hw_breakpoint_used_count): Count resources used by all locations
+       in a breakpoint, and use breakpoint_ops.resources_needed if
+       available.
+       (breakpoint_hit_ranged_breakpoint): New function.
+       (resources_needed_ranged_breakpoint): Likewise.
+       (print_it_ranged_breakpoint): Likewise.
+       (print_one_ranged_breakpoint): Likewise.
+       (print_one_detail_ranged_breakpoint): Likewise.
+       (print_mention_ranged_breakpoint): Likewise.
+       (print_recreate_ranged_breakpoint): Likewise.
+       (ranged_breakpoint_ops): New structure.
+       (find_breakpoint_range_end): New function.
+       (break_range_command): Likewise.
+       (delete_breakpoint): Free addr_string_range_end.
+       (update_breakpoint_locations): Add SALS_END argument.  Update
+       all callers.  Calculate breakpoint length if a non-zero SALS_END
+       is given.  Call breakpoint_locations_match instead of
+       breakpoint_address_match.
+       (reset_breakpoint): Find SaL of the end of the range if B is a
+       ranged breakpoint.
+       (_initialize_breakpoint): Register break-range command.
+       * defs.h (print_core_address): Add function prototype.
+       * ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
+       function.
+       (ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
+       (ppc_linux_remove_hw_breakpoint): Likewise.
+       (_initialize_ppc_linux_nat): Initialize
+       to_ranged_break_num_registers.
+       * target.c (update_current_target): Add comment about
+       to_ranged_break_num_registers.
+       (target_ranged_break_num_registers): New function.
+       * target.h (struct target_ops) <to_ranged_break_num_registers>:
+       New method.
+       (target_ranged_break_num_registers): Add function prototype.
+       * ui-out.c (ui_out_field_core_addr): Move address-printing logic to ...
+       * utils.c (print_core_address): ... here.
+
 2011-03-31  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * breakpoint.c (addr_string_to_sals): Avoid uninitialized
index a09395c7757c6b66d2d44ce5b292c4cb5dbab8a6..8692e2f7c74f0d4d2a614d2a8f99efd88a53d371 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
+  which stop execution of the inferior whenever it executes an instruction
+  at any address within the specified range.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
index 5728ac802be31096ef3e96f5d843aa5a1d677373..2063f3de3c813fb32ae6df588bbb93dd3b80e31f 100644 (file)
@@ -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
 };
index ed7c1c1a38ee61ffa3879d945301d3f3b11dac17..863198fa532f35e54251004a8822e23b4b573def 100644 (file)
@@ -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);
@@ -1537,6 +1541,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)
@@ -2799,11 +2804,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)
@@ -2828,8 +2832,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;
@@ -2853,8 +2856,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)
@@ -2971,8 +2973,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)
@@ -3860,6 +3861,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))
@@ -3888,7 +3892,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)
@@ -3899,13 +3903,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;
 }
 
@@ -4265,8 +4262,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.  */
@@ -4952,9 +4948,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);
@@ -5537,6 +5536,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.  */
@@ -5559,8 +5591,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
@@ -6201,9 +6235,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
@@ -6272,6 +6307,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
 };
@@ -6298,9 +6334,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
@@ -6368,6 +6405,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
 };
@@ -6457,12 +6495,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;
@@ -6531,7 +6571,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;
 
@@ -6652,6 +6692,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
 };
@@ -6747,9 +6788,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
@@ -6806,6 +6848,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
 };
@@ -6829,13 +6872,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;
@@ -8303,6 +8355,309 @@ stopat_command (char *arg, int from_tty)
     break_command_1 (arg, 0, from_tty);
 }
 
+/* Implement the "breakpoint_hit" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+                                 struct address_space *aspace,
+                                 CORE_ADDR bp_addr)
+{
+  return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+                                        bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+  return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  annotate_breakpoint (b->number);
+  if (b->disposition == disp_del)
+    ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+  else
+    ui_out_text (uiout, "\nRanged breakpoint ");
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+                     async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+    }
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
+
+  return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+                            struct bp_location **last_loc)
+{
+  struct bp_location *bl = b->loc;
+  struct value_print_options opts;
+
+  /* Ranged breakpoints have only one location.  */
+  gdb_assert (bl && bl->next == NULL);
+
+  get_user_print_options (&opts);
+
+  if (opts.addressprint)
+    /* We don't print the address range here, it will be printed later
+       by print_one_detail_ranged_breakpoint.  */
+    ui_out_field_skip (uiout, "addr");
+  annotate_field (5);
+  print_breakpoint_location (b, bl);
+  *last_loc = bl;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+                                   struct ui_out *uiout)
+{
+  CORE_ADDR address_start, address_end;
+  struct bp_location *bl = b->loc;
+  struct ui_stream *stb = ui_out_stream_new (uiout);
+  struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
+
+  gdb_assert (bl);
+
+  address_start = bl->address;
+  address_end = address_start + bl->length - 1;
+
+  ui_out_text (uiout, "\taddress range: ");
+  fprintf_unfiltered (stb->stream, "[%s, %s]",
+                     print_core_address (bl->gdbarch, address_start),
+                     print_core_address (bl->gdbarch, address_end));
+  ui_out_field_stream (uiout, "addr", stb);
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (cleanup);
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b)
+{
+  struct bp_location *bl = b->loc;
+
+  gdb_assert (bl);
+  gdb_assert (b->type == bp_hardware_breakpoint);
+
+  if (ui_out_is_mi_like_p (uiout))
+    return;
+
+  printf_filtered (_("Hardware assisted ranged breakpoint %d from %s to %s."),
+                  b->number, paddress (bl->gdbarch, bl->address),
+                  paddress (bl->gdbarch, bl->address + bl->length - 1));
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   ranged breakpoints.  */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
+                     b->addr_string_range_end);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints.  */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+  NULL, /* insert */
+  NULL, /* remove */
+  breakpoint_hit_ranged_breakpoint,
+  resources_needed_ranged_breakpoint,
+  print_it_ranged_breakpoint,
+  print_one_ranged_breakpoint,
+  print_one_detail_ranged_breakpoint,
+  print_mention_ranged_breakpoint,
+  print_recreate_ranged_breakpoint
+};
+
+/* Find the address where the end of the breakpoint range should be
+   placed, given the SAL of the end of the range.  This is so that if
+   the user provides a line number, the end of the range is set to the
+   last instruction of the given line.  */
+
+static CORE_ADDR
+find_breakpoint_range_end (struct symtab_and_line sal)
+{
+  CORE_ADDR end;
+
+  /* If the user provided a PC value, use it.  Otherwise,
+     find the address of the end of the given location.  */
+  if (sal.explicit_pc)
+    end = sal.pc;
+  else
+    {
+      int ret;
+      CORE_ADDR start;
+
+      ret = find_line_pc_range (sal, &start, &end);
+      if (!ret)
+       error (_("Could not find location of the end of the range."));
+
+      /* find_line_pc_range returns the start of the next line.  */
+      end--;
+    }
+
+  return end;
+}
+
+/* Implement the "break-range" CLI command.  */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+  char *arg_start, *addr_string_start, *addr_string_end;
+  struct linespec_result canonical_start, canonical_end;
+  int bp_count, can_use_bp, length;
+  CORE_ADDR end;
+  struct breakpoint *b;
+  struct symtab_and_line sal_start, sal_end;
+  struct symtabs_and_lines sals_start, sals_end;
+  struct cleanup *cleanup_bkpt;
+
+  /* We don't support software ranged breakpoints.  */
+  if (target_ranged_break_num_registers () < 0)
+    error (_("This target does not support hardware ranged breakpoints."));
+
+  bp_count = hw_breakpoint_used_count ();
+  bp_count += target_ranged_break_num_registers ();
+  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+                                                  bp_count, 0);
+  if (can_use_bp < 0)
+    error (_("Hardware breakpoints used exceeds limit."));
+
+  if (arg == NULL || arg[0] == '\0')
+    error(_("No address range specified."));
+
+  sals_start.sals = NULL;
+  sals_start.nelts = 0;
+  init_linespec_result (&canonical_start);
+
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  parse_breakpoint_sals (&arg, &sals_start, &canonical_start, NULL);
+
+  sal_start = sals_start.sals[0];
+  addr_string_start = canonical_start.canonical[0];
+  cleanup_bkpt = make_cleanup (xfree, addr_string_start);
+  xfree (sals_start.sals);
+  xfree (canonical_start.canonical);
+
+  if (arg[0] != ',')
+    error (_("Too few arguments."));
+  else if (sals_start.nelts == 0)
+    error (_("Could not find location of the beginning of the range."));
+  else if (sals_start.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  resolve_sal_pc (&sal_start);
+
+  arg++;       /* Skip the comma.  */
+  while (*arg == ' ' || *arg == '\t')
+    arg++;
+
+  /* Parse the end location.  */
+
+  sals_end.sals = NULL;
+  sals_end.nelts = 0;
+  init_linespec_result (&canonical_end);
+  arg_start = arg;
+
+  /* We call decode_line_n1 directly here instead of using
+     parse_breakpoint_sals because we need to specify the start location's
+     symtab and line as the default symtab and line for the end of the
+     range.  This makes it possible to have ranges like "foo.c:27, +14",
+     where +14 means 14 lines from the start location.  */
+  sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
+                           &canonical_end, NULL);
+
+  /* canonical_end can be NULL if it was of the form "*0xdeadbeef".  */
+  if (canonical_end.canonical == NULL)
+    canonical_end.canonical = xcalloc (1, sizeof (char **));
+  /* Add the string if not present.  */
+  if (arg_start != arg && canonical_end.canonical[0] == NULL)
+    canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
+
+  sal_end = sals_end.sals[0];
+  addr_string_end = canonical_end.canonical[0];
+  make_cleanup (xfree, addr_string_end);
+  xfree (sals_end.sals);
+  xfree (canonical_end.canonical);
+
+  if (sals_end.nelts == 0)
+    error (_("Could not find location of the end of the range."));
+  else if (sals_end.nelts != 1)
+    error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+  resolve_sal_pc (&sal_end);
+
+  end = find_breakpoint_range_end (sal_end);
+  if (sal_start.pc > end)
+    error (_("Invalid address range, end preceeds start."));
+
+  length = end - sal_start.pc + 1;
+  if (length < 0)
+    /* Length overflowed.  */
+    error (_("Address range too large."));
+  else if (length == 1)
+    {
+      /* This range is simple enough to be handled by
+        the `hbreak' command.  */
+      hbreak_command (addr_string_start, 1);
+
+      do_cleanups (cleanup_bkpt);
+
+      return;
+    }
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (get_current_arch (), sal_start,
+                         bp_hardware_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->disposition = disp_donttouch;
+  b->addr_string = addr_string_start;
+  b->addr_string_range_end = addr_string_end;
+  b->ops = &ranged_breakpoint_ops;
+  b->loc->length = length;
+
+  discard_cleanups (cleanup_bkpt);
+
+  mention (b);
+  update_global_location_list (1);
+}
+
 /*  Return non-zero if EXP is verified as constant.  Returned zero
     means EXP is variable.  Also the constant detection may fail for
     some constant expressions and in such case still falsely return
@@ -8455,6 +8810,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   resources_needed_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
@@ -9233,6 +9589,7 @@ static struct breakpoint_ops gnu_v3_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
 };
@@ -10179,6 +10536,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);
@@ -10473,14 +10831,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.  */
+
 void
 update_breakpoint_locations (struct breakpoint *b,
-                            struct symtabs_and_lines sals)
+                            struct symtabs_and_lines sals,
+                            struct symtabs_and_lines sals_end)
 {
   int i;
-  char *s;
   struct bp_location *existing_locations = b->loc;
 
+  /* Ranged breakpoints have only one start location and one end location.  */
+  gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+
   /* If there's no new locations, and all existing locations are
      pending, don't do anything.  This optimizes the common case where
      all locations are in the same shared library, that was unloaded.
@@ -10501,6 +10866,7 @@ update_breakpoint_locations (struct breakpoint *b,
         old symtab.  */
       if (b->cond_string != NULL)
        {
+         char *s;
          struct gdb_exception e;
 
          s = b->cond_string;
@@ -10527,6 +10893,13 @@ update_breakpoint_locations (struct 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.  */
@@ -10552,8 +10925,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;
@@ -10673,8 +11045,9 @@ static void
 re_set_breakpoint (struct breakpoint *b)
 {
   int found;
-  struct symtabs_and_lines sals;
+  struct symtabs_and_lines sals, sals_end;
   struct symtabs_and_lines expanded = {0};
+  struct symtabs_and_lines expanded_end = {0};
   struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
 
   input_radix = b->input_radix;
@@ -10689,7 +11062,17 @@ re_set_breakpoint (struct breakpoint *b)
       expanded = expand_line_sal_maybe (sals.sals[0]);
     }
 
-  update_breakpoint_locations (b, expanded);
+  if (b->addr_string_range_end)
+    {
+      sals_end = addr_string_to_sals (b, b->addr_string_range_end, &found);
+      if (found)
+       {
+         make_cleanup (xfree, sals_end.sals);
+         expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+       }
+    }
+
+  update_breakpoint_locations (b, expanded, expanded_end);
   do_cleanups (cleanups);
 }
 
@@ -12733,7 +13116,23 @@ inferior in all-stop mode, gdb behaves 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);
index 2cb56b744884916e2b33b09a198d4ef65c3039f5..18a7ce791ae5f088e63714409585e5d0e3f8b1e3 100644 (file)
@@ -231,6 +231,10 @@ struct bp_target_info
      is used to determine the type of breakpoint to insert.  */
   CORE_ADDR placed_address;
 
+  /* If this is a ranged breakpoint, then this field contains the
+     length of the range that will be watched for execution.  */
+  int length;
+
   /* If the breakpoint lives in memory and reading that memory would
      give back the breakpoint, instead of the original contents, then
      the original contents are cached here.  Only SHADOW_LEN bytes of
@@ -339,7 +343,8 @@ struct bp_location
   CORE_ADDR address;
 
   /* For hardware watchpoints, the size of the memory region being
-     watched.  */
+     watched.  For hardware ranged breakpoints, the size of the
+     breakpoint range.  */
   int length;
 
   /* Type of hardware watchpoint.  */
@@ -397,7 +402,8 @@ struct breakpoint_ops
 
   /* Return non-zero if the debugger should tell the user that this
      breakpoint was hit.  */
-  int (*breakpoint_hit) (struct breakpoint *);
+  int (*breakpoint_hit) (const struct bp_location *, struct address_space *,
+                        CORE_ADDR);
 
   /* Tell how many hardware resources (debug registers) are needed
      for this breakpoint.  If this function is not provided, then
@@ -412,6 +418,20 @@ struct breakpoint_ops
      breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".
+
+     In the example below, the "address range" line was printed
+     by print_one_detail_ranged_breakpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw breakpoint  keep y              in main at test-watch.c:70
+            address range: [0x10000458, 0x100004c7]
+
+   */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it
      (roughly speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -502,6 +522,11 @@ struct breakpoint
 
     /* String we used to set the breakpoint (malloc'd).  */
     char *addr_string;
+
+    /* For a ranged breakpoint, the string we used to find
+       the end of the range (malloc'd).  */
+    char *addr_string_range_end;
+
     /* Architecture we used to set the breakpoint.  */
     struct gdbarch *gdbarch;
     /* Language we used to set the breakpoint.  */
@@ -904,7 +929,8 @@ extern int breakpoint_thread_match (struct address_space *,
 extern void until_break_command (char *, int, int);
 
 extern void update_breakpoint_locations (struct breakpoint *b,
-                                        struct symtabs_and_lines sals);
+                                        struct symtabs_and_lines sals,
+                                        struct symtabs_and_lines sals_end);
 
 extern void breakpoint_re_set (void);
 
index 9409dde9a7dbea1fe1e7281f5fb638f751ab33f9..9531c5adadde845462f8a1b857ecd89ab32e644c 100644 (file)
@@ -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 */
index 08d6c8c4a4f70fb513c8f0b5d19202d365658c58..424f5c23f7c8c1f8c9678a4719c6718bc5e5142e 100644 (file)
@@ -1,3 +1,9 @@
+2011-03-31  Thiago Jung Bauermann  <bauerman@br.ibm.com>
+           Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
+
+       Implement support for PowerPC BookE ranged breakpoints.
+       * gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.
+
 2011-03-28  Tom Tromey  <tromey@redhat.com>
 
        * gdb.texinfo (Set Tracepoints): Fix typo.
@@ -9,7 +15,7 @@
 
 2011-03-18  Phil Muldoon  <pmuldoon@redhat.com>
 
-        PR python/12149
+       PR python/12149
 
        * gdb.texinfo (Basic Python): Update gdb.write and flush text.
 
index a4e976f3522df80e3a898efa93f91593a489f543..e72a3056ef365b9f5e0e766275d57d798be4d10b 100644 (file)
@@ -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
index 68bed7ebca7312628b189ec7a6b94d23e741bc42..b9cfa136fe4e4945f78a9e43e3aefacc66c11408 100644 (file)
@@ -1011,7 +1011,7 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
   struct value *value;
   CORE_ADDR resolved_address, resolved_pc;
   struct symtab_and_line sal;
-  struct symtabs_and_lines sals;
+  struct symtabs_and_lines sals, sals_end;
 
   gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
 
@@ -1050,9 +1050,10 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
   sal = find_pc_line (resolved_pc, 0);
   sals.nelts = 1;
   sals.sals = &sal;
+  sals_end.nelts = 0;
 
   b->type = bp_breakpoint;
-  update_breakpoint_locations (b, sals);
+  update_breakpoint_locations (b, sals, sals_end);
 }
 
 struct build_id
index 049cde8d96cc95b39726c4d311a1130d01ab559f..f0c7f61388b2107498578defd9aad094d0f776eb 100644 (file)
@@ -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;
index 45259fd216edef5422cad213b0d42d98fe7bbc9a..a032052229f87859a3540b9b4c6e616d390e9d2f 100644 (file)
@@ -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)
 {
index 237d1aae35120b2153538af34fadeec096cd686d..f0b2e43fe7daac6337c2af7b8eebbb887b4694e6 100644 (file)
@@ -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.  */
index 2cd1a5471f36371056ef5ed80fbb41bee04d1c67..59aaa24ea4fc3524682e246e9c7ac85589721d35 100644 (file)
@@ -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
index e688d19b55802f36a9d6fcb45480f25e227a3052..496c9dca29c416aa7eb8c407f3d3a7ffabf5eeed 100644 (file)
@@ -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)
 {