This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH 4/4] Support ranged and masked breakpoints
- From: Thiago Jung Bauermann <bauerman at br dot ibm dot com>
- To: gdb-patches at sourceware dot org
- Cc: Luis Machado <luisgpm at linux dot vnet dot ibm dot com>, Matt Tyrlik <tyrlik at us dot ibm dot com>
- Date: Thu, 31 Dec 2009 15:21:24 -0200
- Subject: Re: [PATCH 4/4] Support ranged and masked breakpoints
- References: <200912232231.10889.bauerman@br.ibm.com>
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);