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: [PATCH 4/4] Support ranged and masked breakpoints


On Wed 23 Dec 2009 22:31:10 Thiago Jung Bauermann wrote:
> Adds support for the following types of breakpoints

This version incorporates all the feedback received so far.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


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

	* breakpoint.c (insert_bp_location): Propagate length of ranged
	breakpoint to its target_info element.
	(breakpoint_here_p): Update check for ranged breakpoints.
	(print_it_typical): Handle printing of ranged breakpoints.
	(bpstat_check_location): Handle the case of a hardware ranged
	breakpoint.
	(print_one_breakpoint_location): Ditto.
	(breakpoint_1): Ditto.
	(breakpoint_address_match_range): New function.
	(set_raw_breakpoint): Set the breakpoint range to zero.
	(hw_breakpoint_used_count): Call target-specific function to tell
	how many extra slots a hardware breakpoint needs.
	(mention): Mention ranged breakpoints.
	(hbreak_range_command): New function.
	(_initialize_breakpoint): Register hbreak-range command.
	* breakpoint.h (hw_point_flag) <HW_POINT_RANGED_BREAK>: New value.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point_p): Handle the
	HW_POINT_RANGED_BREAK case.
	(ppc_linux_insert_hw_breakpoint): Handle inserting ranged breakpoints.
	(ppc_linux_remove_hw_breakpoint): Handle removing ranged breakpoints.
	(ppc_linux_hw_point_extra_slot_count): Handle the
	HW_POINT_RANGED_BREAK case.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	* ui-out.h (ui_out_field_range_core_addr): Declare.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 66e0c8e..97f5ad8 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -127,6 +127,12 @@ static int breakpoint_address_match (struct address_space *aspace1,
 				     struct address_space *aspace2,
 				     CORE_ADDR addr2);
 
+static int breakpoint_address_match_range (struct address_space *aspace1,
+					   CORE_ADDR addr1,
+					   CORE_ADDR len1,
+					   struct address_space *aspace2,
+					   CORE_ADDR addr2);
+
 static void breakpoints_info (char *, int);
 
 static void breakpoint_1 (int, int);
@@ -1334,6 +1340,7 @@ insert_bp_location (struct bp_location *bpt,
   memset (&bpt->target_info, 0, sizeof (bpt->target_info));
   bpt->target_info.placed_address = bpt->address;
   bpt->target_info.placed_address_space = bpt->pspace->aspace;
+  bpt->target_info.length = bpt->ranged_hw_bp_length;
 
   if (bpt->loc_type == bp_loc_software_breakpoint
       || bpt->loc_type == bp_loc_hardware_breakpoint)
@@ -2326,8 +2333,15 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
 
       if ((breakpoint_enabled (bpt->owner)
 	   || bpt->owner->enable_state == bp_permanent)
-	  && breakpoint_address_match (bpt->pspace->aspace, bpt->address,
-				       aspace, pc))
+	  && ((breakpoint_address_match (bpt->pspace->aspace, bpt->address,
+					aspace, pc) && ((bpt->address == pc)))
+	       || (bpt->owner->hw_point_flag == HW_POINT_RANGED_BREAK
+		   && breakpoint_address_match_range (bpt->pspace->aspace,
+						      bpt->address,
+						      bpt->ranged_hw_bp_length,
+						      aspace, pc)
+		   && pc >= bpt->address
+		   && pc < (bpt->address + bpt->ranged_hw_bp_length))))
 	{
 	  if (overlay_debugging 
 	      && section_is_overlay (bpt->section) 
@@ -2898,6 +2912,11 @@ print_it_typical (bpstat bs)
       annotate_breakpoint (b->number);
       if (bp_temp) 
 	ui_out_text (uiout, "\nTemporary breakpoint ");
+      else if (bl && bl->owner
+	       && bl->owner->hw_point_flag == HW_POINT_RANGED_BREAK)
+	ui_out_text (uiout, "\nRange hardware assisted breakpoint ");
+      else if (b->type == bp_hardware_breakpoint)
+	ui_out_text (uiout, "\nHardware assisted breakpoint ");
       else
 	ui_out_text (uiout, "\nBreakpoint ");
       if (ui_out_is_mi_like_p (uiout))
@@ -3457,7 +3476,10 @@ bpstat_check_location (const struct bp_location *bl,
   
   if (b->type == bp_hardware_breakpoint)
     {
-      if (bl->address != bp_addr)
+      if ((b->hw_point_flag == HW_POINT_NONE && bl->address != bp_addr)
+	   || (b->hw_point_flag == HW_POINT_RANGED_BREAK
+	       && (bp_addr < bl->address
+		   || (bp_addr >= bl->address + bl->ranged_hw_bp_length))))
 	return 0;
       if (overlay_debugging		/* unmapped overlay section */
 	  && section_is_overlay (bl->section) 
@@ -4225,7 +4247,13 @@ print_one_breakpoint_location (struct breakpoint *b,
   if (opts.addressprint)
     {
       if (print_address_bits <= 32)
-	strcat (wrap_indent, "           ");
+	{
+	  if (loc && loc->owner
+	      && loc->owner->hw_point_flag == HW_POINT_RANGED_BREAK)
+	    strcat (wrap_indent, "                   ");
+	  else
+	    strcat (wrap_indent, "           ");
+	}
       else
 	strcat (wrap_indent, "                   ");
     }
@@ -4283,8 +4311,14 @@ print_one_breakpoint_location (struct breakpoint *b,
 	    else if (b->loc == NULL || loc->shlib_disabled)
 	      ui_out_field_string (uiout, "addr", "<PENDING>");
 	    else
-	      ui_out_field_core_addr (uiout, "addr",
-				      loc->gdbarch, loc->address);
+	      if (loc && loc->owner
+		  && loc->owner->hw_point_flag == HW_POINT_RANGED_BREAK)
+		ui_out_field_range_core_addr (uiout, "addr", loc->gdbarch,
+					      loc->address,
+					      loc->address + loc->ranged_hw_bp_length);
+	      else
+		ui_out_field_core_addr (uiout, "addr",
+					loc->gdbarch, loc->address);
 	  }
 	annotate_field (5);
 	if (!header_of_multiple)
@@ -4620,7 +4654,10 @@ breakpoint_1 (int bnum, int allflag)
 	  if (nr_printable_breakpoints > 0)
 	    annotate_field (4);
 	  if (print_address_bits <= 32)
-	    ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */
+	    if (b && b->hw_point_flag == HW_POINT_RANGED_BREAK)
+	      ui_out_table_header (uiout, 18, ui_left, "addr", "Address");
+	    else
+	      ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */
 	  else
 	    ui_out_table_header (uiout, 18, ui_left, "addr", "Address");/* 5 */
 	}
@@ -4809,6 +4846,23 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
 	  && addr1 == addr2);
 }
 
+/* Returns true if {ASPACE1,ADDR1} and {ASPACE2,ADDR2} represent the
+   same breakpoint location, but (ADDR1 <= ADDR2 <= ADDR1 + LEN1).
+   In most targets, this can only be true if ASPACE1 matches ASPACE2.
+   On targets that have global breakpoints, the address space
+   doesn't really matter.  */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+				CORE_ADDR len1,
+				struct address_space *aspace2, CORE_ADDR addr2)
+{
+  return ((gdbarch_has_global_breakpoints (target_gdbarch)
+	   || aspace1 == aspace2)
+	  && addr2 >= addr1
+	  && addr2 <= addr1 + len1);
+}
+
 /* Assuming LOC1 and LOC2's types' have meaningful target addresses
    (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
    represent the same location.  */
@@ -5070,6 +5124,7 @@ set_raw_breakpoint (struct gdbarch *gdbarch,
   /* Store the program space that was used to set the breakpoint, for
      breakpoint resetting.  */
   b->pspace = sal.pspace;
+  b->loc->ranged_hw_bp_length = 0;
 
   if (sal.symtab == NULL)
     b->source_file = NULL;
@@ -5900,7 +5955,12 @@ hw_breakpoint_used_count (void)
   ALL_BREAKPOINTS (b)
   {
     if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
-      i++;
+      {
+	i++;
+	/* Special types of hardware breakpoints can use more than
+	   one slot.  */
+	i += target_hw_point_extra_slot_count (b->hw_point_flag);
+      }
   }
 
   return i;
@@ -6197,6 +6257,9 @@ mention (struct breakpoint *b)
 	    say_where = 0;
 	    break;
 	  }
+
+	if (b->hw_point_flag == HW_POINT_RANGED_BREAK)
+	  printf_filtered (_("Range "));
 	printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
 	say_where = 1;
 	break;
@@ -7762,6 +7825,132 @@ rwatch_range_command (char *arg, int from_tty)
   watch_range_command_1 (arg, bp_read_watchpoint, from_tty);
 }
 
+static void
+hbreak_range_command (char *arg, int from_tty)
+{
+  int bp_count, can_use_bp, ret, err;
+  int parse_line = 0;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct symtab_and_line sal;
+  struct gdbarch *gdbarch = get_current_arch ();
+
+  /* Do we support ranged hardware breakpoints?  */
+  if (!target_can_use_special_hw_point_p (HW_POINT_RANGED_BREAK))
+    error (_("This target does not support ranged hardware breakpoints."));
+
+  if (arg != NULL && *arg != '\0')
+    {
+      while (isspace (*arg))
+	arg++;
+
+      /* Is this an address (of the form `0x...'), or a line?  */
+      if (arg[0] == '0' && arg[1] == 'x')
+	parse_line = 0;
+      else
+	parse_line = 1;
+    }
+
+  if (parse_line)
+    {
+      char *l1 = arg, *l2;
+      char *line1, *line2;
+      int size;
+      struct symtabs_and_lines sals1, sals2;
+      struct symtab_and_line sal1, sal2;
+
+      l2 = arg;
+      while (*l2 != ',')
+	l2++;
+
+      size = l2 - l1;
+
+      *l2 = '\0';
+      l2++;
+      while (isspace (*l2))
+	l2++;
+
+      line1 = l1;
+      line2 = l2;
+
+      /* Parsing first line.  */
+      sals1 = decode_line_1 (&line1, 1, NULL, 0, NULL, NULL);
+
+      if (sals1.nelts != 1)
+	error (_("Could not get information on specified line `%s'."), line1);
+      sal1 = sals1.sals[0];
+      xfree (sals1.sals);
+
+      if (*line1)
+	error (_("Junk at end of arguments."));
+
+      resolve_sal_pc (&sal1);
+
+      /* Parsing second line.  */
+      sals2 = decode_line_1 (&line2, 1, NULL, 0, NULL, NULL);
+
+      if (sals2.nelts != 1)
+	error (_("Could not get information on specified line `%s'."), line2);
+      sal2 = sals2.sals[0];
+      xfree (sals2.sals);
+
+      if (*line2)
+	error (_("Junk at end of arguments."));
+
+      resolve_sal_pc (&sal2);
+
+      /* Verifying if the lines make sense.  We need to check if
+	 the first address in the range is smaller than the second,
+	 and also compute the length.  */
+      if (sal1.pc > sal2.pc)
+	error (_("Invalid search space, end preceeds start."));
+
+      start_addr = sal1.pc;
+      length = sal2.pc - sal1.pc;
+
+      if (length == 0)
+	{
+	  /* This range is simple enough to be handled by
+	     the `hbreak' command.  */
+	  hbreak_command (l1, 1);
+	  return;
+	}
+    }
+  else
+    parse_addr_range (&arg, &start_addr, &length);
+
+  bp_count = hw_breakpoint_used_count ();
+  /* For ranged hardware breakpoints, we may have to use 2 slots
+     instead of 1.  */
+  bp_count += target_hw_point_extra_slot_count (HW_POINT_RANGED_BREAK);
+  can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+						   bp_count + 1, 0);
+  if (can_use_bp < 0)
+    error (_("Hardware breakpoints used exceeds limit."));
+
+  sal = find_pc_line (start_addr, 0);
+  sal.pc = start_addr;
+  sal.section = find_pc_overlay (start_addr);
+  sal.explicit_pc = 1;
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, bp_hardware_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = NULL;
+  b->exp_string = NULL;
+  b->val = NULL;
+  b->val_valid = 0;
+  b->hw_point_flag = HW_POINT_RANGED_BREAK;
+  b->loc->ranged_hw_bp_length = length;
+
+  mention (b);
+  update_global_location_list (1);
+}
 
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -11205,6 +11394,17 @@ The watchpoint will stop execution of your program whenever the inferior\n\
 reads any address within the [start-address, end-address] interval."));
   set_cmd_completer (c, expression_completer);
 
+  add_com ("hbreak-range", class_breakpoint, hbreak_range_command, _("\
+Set a hardware assisted breakpoint for an address range.\n\
+The address range should be specified in one of the following formats:\n\
+\n\
+   start-address, end-address\n\
+   start-address, +length\n\
+   start-line, end-line\n\
+\n\
+The breakpoint will stop execution of your program whenever the inferior\n\
+executes any address within the [start-address, end-address] interval."));
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 48b6264..4e49473 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -401,6 +401,7 @@ DEF_VEC_P(bp_location_p);
 enum hw_point_flag {
 	HW_POINT_NONE = 0,
 	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
+	HW_POINT_RANGED_BREAK, /* Hardware ranged breakpoint.  */
 	HW_POINT_MASKED_WATCH, /* Hardware masked watchpoint.  */
 	HW_POINT_COND_HW_ACCEL,   /* Hardware watchpoint with condition
 				  hardware-accelerated.  */
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 1d072e5..c57bb11 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1454,6 +1454,8 @@ ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
 
   switch (flag)
     {
+    case HW_POINT_RANGED_BREAK:
+      return features & PPC_DEBUG_FEATURE_INSN_BP_RANGE;
     case HW_POINT_RANGED_WATCH:
       return features & PPC_DEBUG_FEATURE_DATA_BP_RANGE;
     case HW_POINT_MASKED_WATCH:
@@ -1624,25 +1626,38 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
 				  struct bp_target_info *bp_tgt)
 {
   struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
   ptid_t ptid;
 
   if (!have_ptrace_new_debug_booke)
     return -1;
 
-  ALL_LWPS (lp, ptid)
-    {
-      struct ppc_hw_breakpoint p;
+  if (bp_tgt->length == 0)
+    ALL_LWPS (lp, ptid)
+      {
+	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;
 
-      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;
+	booke_insert_point (&p, TIDGET (ptid));
+      }
+  else
+    ALL_LWPS (lp, ptid)
+      {
+	p.version         = PPC_DEBUG_CURRENT_VERSION;
+	p.trigger_type    = PPC_BREAKPOINT_TRIGGER_EXECUTE;
+	p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+	p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+	p.addr            = (uint64_t) bp_tgt->placed_address;
+	p.addr2           = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+	p.condition_value = 0;
 
-      booke_insert_point (&p, TIDGET (ptid));
-    }
+	booke_insert_point (&p, TIDGET (ptid));
+      }
 
   return 0;
 }
@@ -1652,25 +1667,38 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
 				  struct bp_target_info *bp_tgt)
 {
   struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
   ptid_t ptid;
 
   if (!have_ptrace_new_debug_booke)
     return -1;
 
-  ALL_LWPS (lp, ptid)
-    {
-      struct ppc_hw_breakpoint p;
+  if (bp_tgt->length == 0)
+    ALL_LWPS (lp, ptid)
+      {
+	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;
 
-      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;
+	booke_remove_point (&p, TIDGET (ptid));
+      }
+  else
+    ALL_LWPS (lp, ptid)
+      {
+	p.version         = PPC_DEBUG_CURRENT_VERSION;
+	p.trigger_type    = PPC_BREAKPOINT_TRIGGER_EXECUTE;
+	p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+	p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+	p.addr            = (uint64_t) bp_tgt->placed_address;
+	p.addr2           = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+	p.condition_value = 0;
 
-      booke_remove_point (&p, TIDGET (ptid));
-    }
+	booke_remove_point (&p, TIDGET (ptid));
+      }
 
   return 0;
 }
@@ -2102,13 +2130,15 @@ ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
   /* If this *point is a:
 
      - Masked hardware watchpoint,
-     - Ranged hardware watchpoint
+     - Ranged hardware watchpoint, or
+     - Ranged hardware breakpoint
 
      then it uses 1 extra slot.  */
   switch (flag)
     {
     case HW_POINT_MASKED_WATCH:
     case HW_POINT_RANGED_WATCH:
+    case HW_POINT_RANGED_BREAK:
       return 1;
     default:
       return 0;
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 19a4644..86e7c82 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -486,6 +486,45 @@ ui_out_field_fmt_int (struct ui_out *uiout,
 }
 
 void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR address_end)
+{
+  char addstr[40];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+  {
+    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+  }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 8));
+    strcat (addstr, ",");
+    strcat (addstr, hex_string_custom (address_end, 8));
+    strcat (addstr, "]");
+  }
+  else
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 16));
+    strcat (addstr, ",");
+    strcat (addstr, hex_string_custom (address_end, 16));
+    strcat (addstr, "]");
+  }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
 			struct gdbarch *gdbarch,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 4f3b7a4..43336c4 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -114,6 +114,11 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+extern void ui_out_field_range_core_addr (struct ui_out *uiout, const char *fldname,
+                                          struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR address_end);
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 

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