[PATCH 1/2] Support the new PPC476 processor -- Arch Independent

Sérgio Durigan Júnior
2009-12-16T20:49:03Z

[-- Attachment #1: Type: text/plain, Size: 4240 bytes --]

Hello guys,

This is the patch that modifies the architecture-independent files. It is
responsible for the implementation of the new commands (such as hbreak-range
and watch-range), and the logic that handles the new types of hardware
breakpoints/watchpoints.

Regards,

--
SÃ©rgio Durigan JÃºnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil

gdb/ChangeLog:

2009-16-12 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>

* breakpoint.c (breakpoint_address_match_range): New function.
(update_watchpoint): Added variables to save/restore new fields
for the new types of hardware breakpoints/watchpoints. Disabled
watchpoints before checking the used count. Handled the case when
the hardware supports the acceleration of the watchpoint's condition
evaluation.
(insert_bp_location): Calling the correct insertion method according
to the type of the hardware watchpoint.
(remove_breakpoint_1): Calling the correct deletion method according
to the type of the hardware watchpoint.
(print_it_typical): Handling the various cases when the new types of
hardware breakpoint/watchpoint are going to be printed.
(watchpoints_triggered): Handling the triggering of a hardware masked
watchpoint.
(value_equal_watchpoint): New function.
(watchpoint_check): Calling the correct comparison function for
watchpoints. Handling the case of a hardware mased watchpoint
trigger.
(bpstat_check_location): Handling the case of a hardware ranged
watchpoint.
(bpstat_check_breakpoint_conditions): Handling the case of a hardware
watchpoint with a condition begin hardware-accelerated.
(print_one_breakpoint_location): Handling the case of a hardware
ranged watchpoint.
(breakpoint_1): Ditto.
(set_raw_breakpoint_without_location): Setting the flag to zero.
(set_raw_breakpoint): Setting the range to zero.
(hw_breakpoint_used_count): Added a call to target-specific function
that will tell how many extra slots a hardware breakpoint needs.
(hw_watchpoint_used_count): Ditto, for hardware watchpoints.
(mention): Handling the case when we need to mention special types
of hardware breakpoints/watchpoints.
(watch_command_1): Added a routine to check for the existence of the
`mask' parameter when the user creates a watchpoint. Handling the
creation of special types of hardware watchpoints (masked and
hardware-accelerated condition).
(can_use_hardware_watchpoint): Added code to check if the memory
that is going to be watched is big, i.e., it needs a hardware ranged
watchpoint.
(watch_range_command_1): New function.
(watch_range_command): Ditto.
(awatch_range_command): Ditto.
(rwatch_range_command): Ditto.
(hbreak_range_command): Ditto.
(update_breakpoint_locations): Handling the case of a hardware
watchpoint with a condition begin hardware-accelerated.
(exp_is_address_p): New function.
(exp_is_var_p): Ditto.
(cond_is_address_equal_literal_p): Ditto.
(cond_is_var_equal_literal_p): Ditto.
(get_var_address): Ditto.
(default_watch_address_if_var_equal_literal_p): Ditto.
(default_watch_var_if_address_equal_literal_p): Ditto.
(default_watch_var_if_var_equal_literal_p): Ditto.
(default_watch_address_if_address_equal_literal_p): Ditto.

* breakpoint.h (struct bp_target_info) <length>: New field.
(struct bp_location) <cond_hw_accel>, <cond_hw_addr>,
<ranged_hw_bp_length>, <hw_wp_mask>: New fields.
(enum hw_point_flag): New.
(struct breakpoint) <hw_point_flag>: New field.
(default_watch_address_if_address_equal_literal_p): Declaring.
(default_watch_var_if_var_equal_literal_p): Ditto.
(default_watch_address_if_var_equal_literal_p): Ditto.
(default_watch_var_if_address_equal_literal_p): Ditto.

* findcmd.c (parse_addr_range): New function.
(parse_find_args): Calling `parse_addr_range'.

* ui-out.c (ui_out_field_range_core_addr): New function.

* ui-out.h (ui_out_field_range_core_addr): Declaring.

* value.h (parse_addr_range): Declaring.

gdb/testsuite/ChangeLog:

2009-16-12 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>

* gdb.base/watchpoint.c (buf): Changing the vector size from 10
to 30.
(func3): Assigning a value to `buf'.

* gdb.base/watchpoint.exp (test_watchpoint_in_big_blob): New
procedure.

[-- Attachment #2: ppc476-arch-indep.patch --]
[-- Type: text/x-patch, Size: 57888 bytes --]

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 5394ae4..42f04a3 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);
@@ -1059,6 +1065,8 @@ update_watchpoint (struct breakpoint *b, int reparse)
struct bp_location *loc;
int frame_saved;
bpstat bs;
+ CORE_ADDR mask = 0;
+ ULONGEST range = 0;

/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
@@ -1066,7 +1074,19 @@ update_watchpoint (struct breakpoint *b, int reparse)
if (!watchpoint_in_thread_scope (b))
return;

- /* We don't free locations. They are stored in bp_location array and
+ /* We've got to save some special fields before updating
+ this watchpoint. */
+ switch (b->hw_point_flag)
+ {
+ case HW_POINT_MASKED_WATCH:
+ mask = b->loc->hw_wp_mask;
+ break;
+ case HW_POINT_RANGED_WATCH:
+ range = b->loc->ranged_hw_bp_length;
+ break;
+ }
+
+ /* We don't free locations. They are stored in bp_location_chain and
update_global_locations will eventually delete them and remove
breakpoints if needed. */
b->loc = NULL;
@@ -1100,6 +1120,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
if (within_current_scope && reparse)
{
char *s;
+
if (b->exp)
{
xfree (b->exp);
@@ -1151,6 +1172,13 @@ update_watchpoint (struct breakpoint *b, int reparse)
&& reparse)
{
int i, mem_cnt, other_type_used;
+ enum enable_state e;
+
+ /* We have to temporary disable this watchpoint, otherwise
+ we will count it twice (once as being inserted, and once
+ as a watchpoint that we want to insert). */
+ e = b->enable_state;
+ b->enable_state = bp_disabled;

i = hw_watchpoint_used_count (bp_hardware_watchpoint,
&other_type_used);
@@ -1167,6 +1195,8 @@ update_watchpoint (struct breakpoint *b, int reparse)
else
b->type = bp_hardware_watchpoint;
}
+ /* Restoring the original state. */
+ b->enable_state = e;
}

frame_pspace = get_frame_program_space (get_selected_frame (NULL));
@@ -1229,6 +1259,17 @@ update_watchpoint (struct breakpoint *b, int reparse)
{
char *s = b->cond_string;
b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0);
+
+ if (b->type == bp_hardware_watchpoint
+ && TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_COND_HW_ACCEL)
+ && TARGET_CAN_USE_WATCHPOINT_COND_ACCEL_P (b->loc))
+ {
+ TARGET_GET_WATCHPOINT_COND_ACCEL_ADDR (b->loc,
+ &b->loc->cond_hw_addr);
+ b->hw_point_flag = HW_POINT_COND_HW_ACCEL;
+ }
+ else
+ b->hw_point_flag = HW_POINT_NONE;
}
}
else if (!within_current_scope)
@@ -1242,6 +1283,13 @@ in which its expression is valid.\n"),
b->disposition = disp_del_at_next_stop;
}

+ /* Restoring some special fields. */
+ if (b->loc)
+ {
+ b->loc->hw_wp_mask = mask;
+ b->loc->ranged_hw_bp_length = range;
+ }
+
/* Restore the selected frame. */
if (frame_saved)
select_frame (frame_find_by_id (saved_frame_id));
@@ -1302,6 +1350,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)
@@ -1472,9 +1521,20 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
watchpoints. It's not clear that it's necessary... */
&& bpt->owner->disposition != disp_del_at_next_stop)
{
- val = target_insert_watchpoint (bpt->address,
- bpt->length,
- bpt->watchpoint_type);
+ if (bpt->owner->hw_point_flag == HW_POINT_MASKED_WATCH)
+ val = target_insert_mask_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type,
+ bpt->hw_wp_mask);
+ else if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ val = target_insert_cond_accel_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type,
+ bpt->cond_hw_addr);
+ else
+ val = target_insert_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type);
bpt->inserted = (val != -1);
}

@@ -1613,6 +1673,7 @@ insert_breakpoint_locations (void)
val = insert_bp_location (b, tmp_error_stream,
&disabled_breaks,
&hw_breakpoint_error);
+
if (val)
error = val;
}
@@ -2100,8 +2161,17 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
struct value *n;

b->inserted = (is == mark_inserted);
- val = target_remove_watchpoint (b->address, b->length,
- b->watchpoint_type);
+ if (b->owner->hw_point_flag == HW_POINT_MASKED_WATCH)
+ val = target_remove_mask_watchpoint (b->address, b->length,
+ b->watchpoint_type,
+ b->hw_wp_mask);
+ else if (b->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ val = target_remove_cond_accel_watchpoint (b->address, b->length,
+ b->watchpoint_type,
+ b->cond_hw_addr);
+ else
+ val = target_remove_watchpoint (b->address, b->length,
+ b->watchpoint_type);

/* Failure to remove any of the hardware watchpoints comes here. */
if ((is == mark_uninserted) && (b->inserted))
@@ -2267,8 +2337,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)
@@ -2839,6 +2916,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))
@@ -2887,13 +2969,19 @@ print_it_typical (bpstat bs)
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
mention (b);
- make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nOld value = ");
- watchpoint_value_print (bs->old_val, stb->stream);
- ui_out_field_stream (uiout, "old", stb);
- ui_out_text (uiout, "\nNew value = ");
- watchpoint_value_print (b->val, stb->stream);
- ui_out_field_stream (uiout, "new", stb);
+ if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+ ui_out_text (uiout, "\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n");
+ else
+ {
+ make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ watchpoint_value_print (bs->old_val, stb->stream);
+ ui_out_field_stream (uiout, "old", stb);
+ ui_out_text (uiout, "\nNew value = ");
+ watchpoint_value_print (b->val, stb->stream);
+ ui_out_field_stream (uiout, "new", stb);
+ }
ui_out_text (uiout, "\n");
/* More than one watchpoint may have been triggered. */
result = PRINT_UNKNOWN;
@@ -2905,10 +2993,18 @@ print_it_typical (bpstat bs)
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
mention (b);
- make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nValue = ");
- watchpoint_value_print (b->val, stb->stream);
- ui_out_field_stream (uiout, "value", stb);
+
+ if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+ ui_out_text (uiout, "\nCheck the underlying instruction\
+ at PC for address and value related to this watchpoint trigger.\n");
+ else
+ {
+ make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nValue = ");
+ watchpoint_value_print (b->val, stb->stream);
+ ui_out_field_stream (uiout, "value", stb);
+ }
+
ui_out_text (uiout, "\n");
result = PRINT_UNKNOWN;
break;
@@ -2922,24 +3018,39 @@ print_it_typical (bpstat bs)
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
mention (b);
- make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nOld value = ");
- watchpoint_value_print (bs->old_val, stb->stream);
- ui_out_field_stream (uiout, "old", stb);
- ui_out_text (uiout, "\nNew value = ");
+
+ if (b->hw_point_flag != HW_POINT_MASKED_WATCH)
+ {
+ make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ watchpoint_value_print (bs->old_val, stb->stream);
+ ui_out_field_stream (uiout, "old", stb);
+ ui_out_text (uiout, "\nNew value = ");
+ }
}
else
{
mention (b);
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
- make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nValue = ");
+
+ if (b->hw_point_flag != HW_POINT_MASKED_WATCH)
+ {
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+ make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nValue = ");
+ }
}
- watchpoint_value_print (b->val, stb->stream);
- ui_out_field_stream (uiout, "new", stb);
+ if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+ ui_out_text (uiout, "\nCheck the underlying instruction\
+ at PC for address and value related to this watchpoint trigger.\n");
+ else
+ {
+ watchpoint_value_print (b->val, stb->stream);
+ ui_out_field_stream (uiout, "new", stb);
+ }
+
ui_out_text (uiout, "\n");
result = PRINT_UNKNOWN;
break;
@@ -3148,15 +3259,30 @@ watchpoints_triggered (struct target_waitstatus *ws)

b->watchpoint_triggered = watch_triggered_no;
for (loc = b->loc; loc; loc = loc->next)
- /* Exact match not required. Within range is
- sufficient. */
- if (target_watchpoint_addr_within_range (&current_target,
- addr, loc->address,
- loc->length))
- {
- b->watchpoint_triggered = watch_triggered_yes;
- break;
- }
+ {
+ CORE_ADDR newaddr, start;
+
+ if (loc->owner->hw_point_flag == HW_POINT_MASKED_WATCH)
+ {
+ newaddr = addr & loc->hw_wp_mask;
+ start = loc->address & loc->hw_wp_mask;
+ }
+ else
+ {
+ newaddr = addr;
+ start = loc->address;
+ }
+
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (target_watchpoint_addr_within_range (&current_target,
+ newaddr, start,
+ loc->length))
+ {
+ b->watchpoint_triggered = watch_triggered_yes;
+ break;
+ }
+ }
}

return 1;
@@ -3174,7 +3300,23 @@ watchpoints_triggered (struct target_waitstatus *ws)
#define BP_TEMPFLAG 1
#define BP_HARDWAREFLAG 2

-/* Check watchpoint condition. */
+/* Check watchpoint condition. We can't use value_equal because it coerces
+ an array to a pointer, thus comparing just the address of the array instead
+ of its contents. This is not what we want. */
+
+static int
+value_equal_watchpoint (struct value *arg1, struct value *arg2)
+{
+ struct type *type1, *type2;
+
+ type1 = check_typedef (value_type (arg1));
+ type2 = check_typedef (value_type (arg2));
+
+ return TYPE_CODE (type1) == TYPE_CODE (type2)
+ && TYPE_LENGTH (type1) == TYPE_LENGTH (type2)
+ && memcmp (value_contents (arg1), value_contents (arg2),
+ TYPE_LENGTH (type1)) == 0;
+}

static int
watchpoint_check (void *p)
@@ -3246,7 +3388,7 @@ watchpoint_check (void *p)

fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
if ((b->val != NULL) != (new_val != NULL)
- || (b->val != NULL && !value_equal (b->val, new_val)))
+ || (b->val != NULL && !value_equal_watchpoint (b->val, new_val)))
{
if (new_val != NULL)
{
@@ -3259,6 +3401,10 @@ watchpoint_check (void *p)
/* We will stop here */
return WP_VALUE_CHANGED;
}
+ else if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+ /* Since we don't the exact trigger address (from stopped_data_address)
+ Just tell the user we've triggered a mask watchpoint. */
+ return WP_VALUE_CHANGED;
else
{
/* Nothing changed, don't do anything. */
@@ -3337,7 +3483,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)
@@ -3465,6 +3614,11 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
if (frame_id_p (b->frame_id)
&& !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ())))
bs->stop = 0;
+ else if (b->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ /* The condition is going to be hardware-accelerated, which means
+ that we don't have to evaluate it because the hardware already
+ did this. Just return. */
+ return;
else if (bs->stop)
{
int value_is_zero = 0;
@@ -4097,7 +4251,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, " ");
}
@@ -4155,8 +4315,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)
@@ -4492,7 +4658,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 */
}
@@ -4681,6 +4850,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. */
@@ -4850,6 +5036,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
b->syscalls_to_be_caught = NULL;
b->ops = NULL;
b->condition_not_parsed = 0;
+ b->hw_point_flag = HW_POINT_NONE;

/* Add this breakpoint to the end of the chain
so that a list of breakpoints will come out in order
@@ -4941,6 +5128,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;
@@ -5771,7 +5959,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;
@@ -5789,10 +5982,15 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used)
if (breakpoint_enabled (b))
{
if (b->type == type)
- i++;
- else if ((b->type == bp_hardware_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint))
+ {
+ i++;
+ /* Special types of hardware watchpoints can use more
+ than one slot. */
+ i += target_hw_point_extra_slot_count (b->hw_point_flag);
+ }
+ else if ((b->type == bp_hardware_watchpoint ||
+ b->type == bp_read_watchpoint ||
+ b->type == bp_access_watchpoint))
*other_type_used = 1;
}
}
@@ -6009,6 +6207,10 @@ mention (struct breakpoint *b)
do_cleanups (ui_out_chain);
break;
case bp_hardware_watchpoint:
+ if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+ ui_out_text (uiout, "Mask ");
+ else if (b->hw_point_flag == HW_POINT_RANGED_WATCH)
+ ui_out_text (uiout, "Range ");
ui_out_text (uiout, "Hardware watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
ui_out_field_int (uiout, "number", b->number);
@@ -6017,6 +6219,10 @@ mention (struct breakpoint *b)
do_cleanups (ui_out_chain);
break;
case bp_read_watchpoint:
+ if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+ ui_out_text (uiout, "Mask ");
+ else if (b->hw_point_flag == HW_POINT_RANGED_WATCH)
+ ui_out_text (uiout, "Range ");
ui_out_text (uiout, "Hardware read watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
ui_out_field_int (uiout, "number", b->number);
@@ -6025,6 +6231,10 @@ mention (struct breakpoint *b)
do_cleanups (ui_out_chain);
break;
case bp_access_watchpoint:
+ if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+ ui_out_text (uiout, "Mask ");
+ else if (b->hw_point_flag == HW_POINT_RANGED_WATCH)
+ ui_out_text (uiout, "Range ");
ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
ui_out_field_int (uiout, "number", b->number);
@@ -6051,6 +6261,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;
@@ -7089,74 +7302,143 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
char *exp_start = NULL;
char *exp_end = NULL;
char *tok, *id_tok_start, *end_tok;
- int toklen;
+ int toklen = -1;
char *cond_start = NULL;
char *cond_end = NULL;
int i, other_type_used, target_resources_ok = 0;
enum bptype bp_type;
int mem_cnt = 0;
int thread = -1;
+ /* Flag to indicate whether we are going to use masks for
+ the hardware watchpoint. */
+ int use_mask = 0;
+ CORE_ADDR hw_wp_mask = 0;
+
+ do {
+ /* Make sure that we actually have parameters to parse. */
+ if (arg != NULL && arg[0] != '\0')
+ {
+ toklen = strlen (arg); /* Size of argument list. */

- /* Make sure that we actually have parameters to parse. */
- if (arg != NULL && arg[0] != '\0')
- {
- toklen = strlen (arg); /* Size of argument list. */
-
- /* Points tok to the end of the argument list. */
- tok = arg + toklen - 1;
+ /* Points tok to the end of the argument list. */
+ tok = arg + toklen - 1;

- /* Go backwards in the parameters list. Skip the last parameter.
- If we're expecting a 'thread <thread_num>' parameter, this should
- be the thread identifier. */
- while (tok > arg && (*tok == ' ' || *tok == '\t'))
- tok--;
- while (tok > arg && (*tok != ' ' && *tok != '\t'))
- tok--;
+ /* Go backwards in the parameters list. Skip the last parameter.
+ If we're expecting a 'thread <thread_num>' parameter, this should
+ be the thread identifier. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;

- /* Points end_tok to the beginning of the last token. */
- id_tok_start = tok + 1;
+ /* Points end_tok to the beginning of the last token. */
+ id_tok_start = tok + 1;

- /* Go backwards in the parameters list. Skip one more parameter.
- If we're expecting a 'thread <thread_num>' parameter, we should
- reach a "thread" token. */
- while (tok > arg && (*tok == ' ' || *tok == '\t'))
- tok--;
+ /* Go backwards in the parameters list. Skip one more parameter.
+ If we're expecting a 'thread <thread_num>' parameter, we should
+ reach a "thread" token. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;

- end_tok = tok;
+ end_tok = tok;

- while (tok > arg && (*tok != ' ' && *tok != '\t'))
- tok--;
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;

- /* Move the pointer forward to skip the whitespace and
- calculate the length of the token. */
- tok++;
- toklen = end_tok - tok;
+ /* Move the pointer forward to skip the whitespace and
+ calculate the length of the token. */
+ tok++;
+ toklen = end_tok - tok;

- if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
- {
- /* At this point we've found a "thread" token, which means
- the user is trying to set a watchpoint that triggers
- only in a specific thread. */
- char *endp;
-
- /* Extract the thread ID from the next token. */
- thread = strtol (id_tok_start, &endp, 0);
-
- /* Check if the user provided a valid numeric value for the
- thread ID. */
- if (*endp != ' ' && *endp != '\t' && *endp != '\0')
- error (_("Invalid thread ID specification %s."), id_tok_start);
-
- /* Check if the thread actually exists. */
- if (!valid_thread_id (thread))
- error (_("Unknown thread %d."), thread);
-
- /* Truncate the string and get rid of the thread <thread_num>
- parameter before the parameter list is parsed by the
- evaluate_expression() function. */
- *tok = '\0';
- }
- }
+ if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+ {
+ /* At this point we've found a "thread" token, which means
+ the user is trying to set a watchpoint that triggers
+ only in a specific thread. */
+ char *endp;
+
+ /* Extract the thread ID from the next token. */
+ thread = strtol (id_tok_start, &endp, 0);
+
+ /* Check if the user provided a valid numeric value for the
+ thread ID. */
+ if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+ error (_("Invalid thread ID specification %s."),
+ id_tok_start);
+
+ /* Check if the thread actually exists. */
+ if (!valid_thread_id (thread))
+ error (_("Unknown thread %d."), thread);
+
+ /* Truncate the string and get rid of the thread <thread_num>
+ parameter before the parameter list is parsed by the
+ evaluate_expression() function. */
+ *tok = '\0';
+ }
+ else if (toklen >= 1 && strncmp (tok, "mask", toklen) == 0)
+ {
+ /* We've found a "mask" token, which means the user wants to
+ create a hardware watchpoint that is going to have the mask
+ facility. */
+ char *tokp = tok;
+ char *addr_p;
+ char *endp;
+ char *mask_addr;
+ int len_addr;
+ struct value *mask_value;
+ struct cleanup *clean_mask_addr;
+
+ /* Does the target support masked watchpoints? */
+ if (!TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_MASKED_WATCH))
+ error (_("This target does not support the usage of masks \
+with hardware watchpoints."));
+
+ use_mask = 1;
+
+ /* Skipping the token "mask", and possible spaces. */
+ while (!isspace (*tokp) && *tokp != '\0')
+ tokp++;
+ while (isspace (*tokp))
+ tokp++;
+
+ if (*tokp == '\0')
+ error (_("You must supply the address that is going to be\n\
+used in the mask."));
+ addr_p = tokp;
+
+ while (!isspace (*addr_p) && *addr_p != '\0')
+ addr_p++;
+
+ len_addr = addr_p - tokp;
+
+ strtol (tokp, &endp, 16);
+ /* Check if the user provided a valid numeric value for the
+ mask address. */
+ if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+ error (_("Invalid mask address specification `%s'."),
+ tokp);
+
+ if (len_addr <= 0)
+ error (_("The mask address is invalid."));
+
+ mask_addr = xstrndup (tokp, len_addr);
+ clean_mask_addr = make_cleanup (xfree, mask_addr);
+
+ mask_value = parse_to_comma_and_eval (&mask_addr);
+ hw_wp_mask = value_as_address (mask_value);
+
+ /* Truncate the string and get rid of the "mask "
+ parameter before the parameter list is parsed by the
+ evaluate_expression() function. */
+ *tok = '\0';
+ do_cleanups (clean_mask_addr);
+ }
+ else if (toklen >= 1)
+ /* There is a token, but it is not recognized. We should
+ stop here. */
+ break;
+ }
+ } while (toklen >= 1);

/* Parse the rest of the arguments. */
innermost_block = NULL;
@@ -7208,6 +7490,11 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
error (_("Expression cannot be implemented with read/access watchpoint."));
if (mem_cnt != 0)
{
+ /* If we are going to use masks, then we may need more
+ slots in order to use the hardware watchpoint. */
+ if (use_mask)
+ mem_cnt += target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
target_can_use_hardware_watchpoint (bp_type, i + mem_cnt,
@@ -7222,7 +7509,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
/* Change the type of breakpoint to an ordinary watchpoint if a hardware
watchpoint could not be set. */
if (!mem_cnt || target_resources_ok <= 0)
- bp_type = bp_watchpoint;
+ {
+ if (use_mask)
+ /* No way to implement a watchpoint that uses mask without
+ hardware support. */
+ error (_("Cannot use masks without hardware watchpoints."));
+ else
+ bp_type = bp_watchpoint;
+ }

frame = block_innermost_frame (exp_valid_block);

@@ -7270,6 +7564,12 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
b->val_valid = 1;
+ if (use_mask)
+ {
+ b->loc->hw_wp_mask = hw_wp_mask;
+ b->hw_point_flag = HW_POINT_MASKED_WATCH;
+ }
+
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
@@ -7300,6 +7600,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
that should be inserted. */
update_watchpoint (b, 1);

+ if (b->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ printf_filtered (_("This watchpoint will have its condition evaluation \
+assisted by hardware.\n"));
+
mention (b);
update_global_location_list (1);
}
@@ -7351,21 +7655,25 @@ can_use_hardware_watchpoint (struct value *v)
/* Ahh, memory we actually used! Check if we can cover
it with hardware watchpoints. */
struct type *vtype = check_typedef (value_type (v));
+ /* Is the value a struct or array? */
+ int is_big_blob = TYPE_CODE (vtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (vtype) == TYPE_CODE_ARRAY;

/* We only watch structs and arrays if user asked for it
explicitly, never if they just happen to appear in a
middle of some value chain. */
- if (v == head
- || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
- && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ if (v == head || !is_big_blob)
{
CORE_ADDR vaddr = value_address (v);
int len = TYPE_LENGTH (value_type (v));
+ int ret;

- if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+ ret = TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len,
+ is_big_blob);
+ if (!ret)
return 0;
else
- found_memory_cnt++;
+ found_memory_cnt += ret;
}
}
}
@@ -7416,6 +7724,230 @@ awatch_command (char *arg, int from_tty)
{
watch_command_1 (arg, hw_access, from_tty);
}
+
+static void
+watch_range_command_1 (char *arg, int accessflag, int from_tty)
+{
+ char *exp_string, *string_p;
+ struct gdbarch *gdbarch = get_current_arch ();
+ int wp_count, other_type_used, can_use_wp, ret, err, mem_cnt;
+ CORE_ADDR start_addr;
+ ULONGEST length;
+ struct breakpoint *b;
+ struct expression *exp;
+ struct symtab_and_line sal;
+ struct value *val;
+ struct cleanup *cleanups;
+ enum bptype type;
+
+ /* Do we support ranged hardware watchpoints? */
+ if (!TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_RANGED_WATCH))
+ error (_("This target does not support ranged hardware watchpoints."));
+
+ parse_addr_range (&arg, &start_addr, &length);
+
+ exp_string = string_p = xstrprintf ("{char[%s]} %s",
+ phex (length, sizeof (length)),
+ paddress (gdbarch, start_addr));
+ exp = parse_exp_1 (&string_p, 0, 0);
+ fetch_watchpoint_value (exp, &val, NULL, NULL);
+ if (val != NULL)
+ release_value (val);
+ cleanups = make_cleanup (xfree, exp_string);
+
+ mem_cnt = can_use_hardware_watchpoint (val);
+ if (mem_cnt < 0)
+ error (_("Provided range can't be watched."));
+
+ if (accessflag == hw_read)
+ type = bp_read_watchpoint;
+ else if (accessflag == hw_access)
+ type = bp_access_watchpoint;
+ else
+ type = bp_hardware_watchpoint;
+
+ wp_count = hw_watchpoint_used_count (type,
+ &other_type_used);
+ can_use_wp = target_can_use_hardware_watchpoint (type,
+ wp_count + mem_cnt,
+ other_type_used);
+ if (can_use_wp < 0)
+ error (_("Not enough available hardware watchpoints."));
+
+ init_sal (&sal); /* initialize to zeroes */
+ sal.pspace = current_program_space;
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (gdbarch, sal, accessflag);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->thread = -1;
+ b->disposition = disp_donttouch;
+ b->exp = exp;
+ b->exp_string = exp_string;
+ b->hw_point_flag = HW_POINT_RANGED_WATCH;
+ if (val)
+ {
+ b->val = val;
+ b->val_valid = 1;
+ }
+ b->watchpoint_frame = null_frame_id;
+
+ mention (b);
+ update_global_location_list (1);
+
+ discard_cleanups (cleanups);
+}
+
+static void
+watch_range_command (char *arg, int from_tty)
+{
+ watch_range_command_1 (arg, bp_hardware_watchpoint, from_tty);
+}
+
+static void
+awatch_range_command (char *arg, int from_tty)
+{
+ watch_range_command_1 (arg, bp_access_watchpoint, from_tty);
+}
+
+static void
+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 treated by
+ the `hbreak' command. */
+ printf_unfiltered (_("Range is too small, using `hbreak' \
+instead.\n"));
+ 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 (_("Not enough available hardware breakpoints."));
+
+ 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);
+}
\f

/* Helper routines for the until_command routine in infcmd.c. Here
@@ -8854,6 +9386,18 @@ update_breakpoint_locations (struct breakpoint *b,
b->number, e.message);
new_loc->enabled = 0;
}
+
+ if (b->type == bp_hardware_watchpoint
+ && new_loc->cond
+ && TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_COND_HW_ACCEL)
+ && TARGET_CAN_USE_WATCHPOINT_COND_ACCEL_P (new_loc))
+ {
+ TARGET_GET_WATCHPOINT_COND_ACCEL_ADDR (new_loc,
+ &new_loc->cond_hw_addr);
+ new_loc->owner->hw_point_flag = HW_POINT_COND_HW_ACCEL;
+ }
+ else
+ new_loc->owner->hw_point_flag = HW_POINT_NONE;
}

if (b->source_file != NULL)
@@ -10019,6 +10563,230 @@ tracepoint_save_command (char *args, int from_tty)
return;
}

+/* This function checks if the expression associated
+ with the breakpoint `b' is of the form "* ".
+ It returns 1 if it is, 0 otherwise. */
+static int
+exp_is_address_p (struct breakpoint *b)
+{
+ /* Check that the associated tree corresponds to that expression,
+ that is 5 elements, first a UNOP_IND, and then an OP_LONG. */
+ if (b->exp->nelts != 5
+ || b->exp->elts[0].opcode != UNOP_IND
+ || b->exp->elts[1].opcode != OP_LONG)
+ return 0;
+ return 1;
+}
+
+/* This function checks if the expression associated
+ with the breakpoint `b' is of the form "".
+ It returns 1 if it is, 0 otherwise. */
+static int
+exp_is_var_p (struct breakpoint *b)
+{
+ /* Check that the associated tree corresponds to that expression,
+ that is 4 elements, first a OP_VAR_VALUE. */
+ if (b->exp->nelts != 4
+ || b->exp->elts[0].opcode != OP_VAR_VALUE)
+ return 0;
+ return 1;
+}
+
+/* This function checks if the condition associated
+ with the bp_location `b' is of the form "* == LITERAL".
+ It returns 1 if it is, 0 otherwise. */
+static int
+cond_is_address_equal_literal_p (struct bp_location *b)
+{
+ /* Check the watchpoint condition expression. It should be
+ of the form "* EQUAL <litteral>", where EQUAL is the
+ equality binary operator. The associated tree should have
+ exactly 10 elements in it, all in a very specific order. */
+ if (b->cond->nelts != 10
+ || b->cond->elts[0].opcode != BINOP_EQUAL
+ || b->cond->elts[1].opcode != UNOP_IND
+ || b->cond->elts[2].opcode != OP_LONG
+ || b->cond->elts[6].opcode != OP_LONG)
+ return 0;
+ return 1;
+}
+
+/* This function checks if the condition associated
+ with the bp_location `b' is of the form " == LITERAL".
+ It returns 1 if it is, 0 otherwise. */
+static int
+cond_is_var_equal_literal_p (struct bp_location *b)
+{
+ /* Check the watchpoint condition expression. It should be
+ of the form "<variable> EQUAL <litteral>", where EQUAL is the
+ equality binary operator. The associated tree should have
+ exactly 9 elements in it, all in a very specific order. */
+ if (b->cond->nelts != 9
+ || b->cond->elts[0].opcode != BINOP_EQUAL
+ || b->cond->elts[1].opcode != OP_VAR_VALUE
+ || b->cond->elts[5].opcode != OP_LONG)
+ return 0;
+ return 1;
+}
+
+/* This function returns the address of a variable VAR which
+ resides on the block B. */
+static CORE_ADDR
+get_var_address (struct symbol *var, struct block *b)
+{
+ struct value *v = address_of_variable (var, b);
+ return value_as_address (v);
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch *<ADDRESS> if <VAR> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_address_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ CORE_ADDR exp_address,
+ cond_address;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_address_p (bp)
+ || !cond_is_var_equal_literal_p (b))
+ return 0;
+
+ exp_address = bp->exp->elts[3].longconst;
+ cond_address = get_var_address (b->cond->elts[3].symbol,
+ b->cond->elts[2].block);
+
+ /* Make sure that the two addresses are the same. */
+ if (exp_address != cond_address)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ *data_value = b->cond->elts[7].longconst;
+
+ return 1;
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch <VAR> if *<ADDRESS> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_var_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ CORE_ADDR exp_address,
+ cond_address;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_var_p (bp)
+ || !cond_is_address_equal_literal_p (b))
+ return 0;
+
+ exp_address = get_var_address (bp->exp->elts[2].symbol,
+ bp->exp->elts[1].block);
+ cond_address = b->cond->elts[4].longconst;
+
+ /* Make sure that the two addresses are the same. */
+ if (exp_address != cond_address)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ *data_value = b->cond->elts[8].longconst;
+
+ return 1;
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch <VAR> if <VAR> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_var_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ char *name_exp, *name_cond;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_var_p (bp)
+ || !cond_is_var_equal_literal_p (b))
+ return 0;
+
+ name_exp = bp->exp->elts[2].symbol->ginfo.name;
+ name_cond = b->cond->elts[3].symbol->ginfo.name;
+
+ /* Make sure that the two variables' names are the same. */
+ if (strcmp (name_cond, name_exp) != 0)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ *data_value = b->cond->elts[7].longconst;
+
+ return 1;
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch *<ADDRESS> if *<ADDRESS> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_address_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ CORE_ADDR exp_address,
+ cond_address;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_address_p (bp)
+ || !cond_is_address_equal_literal_p (b))
+ return 0;
+
+ exp_address = bp->exp->elts[3].longconst;
+ cond_address = b->cond->elts[4].longconst;
+
+ /* Make sure that the two addresses are the same. */
+ if (exp_address != cond_address)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ *data_value = b->cond->elts[8].longconst;
+
+ return 1;
+}
+
/* Create a vector of all tracepoints. */

VEC(breakpoint_p) *
@@ -10568,7 +11336,51 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
&show_always_inserted_mode,
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
-
+
+ c = add_com ("watch-range", class_breakpoint, watch_range_command, _("\
+Set a WRITE hardware watchpoint 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\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+writes to any address within that range."));
+ set_cmd_completer (c, expression_completer);
+
+ c = add_com ("awatch-range", class_breakpoint, awatch_range_command, _("\
+Set an ACCESS hardware watchpoint 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\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+accesses (reads from or writes to) any address within that range."));
+ set_cmd_completer (c, expression_completer);
+
+ c = add_com ("rwatch-range", class_breakpoint, rwatch_range_command, _("\
+Set a READ hardware watchpoint 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\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+reads any address within that range."));
+ 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 that range."));
+
automatic_hardware_breakpoints = 1;

observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 5ebd36c..4e49473 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -186,6 +186,11 @@ struct bp_target_info
is used to determine the type of breakpoint to insert. */
CORE_ADDR placed_address;

+ /* If this is a ranged hardware breakpoint, then we can use this
+ field in order to store the length of the range that will be
+ watched for execution. */
+ ULONGEST length;
+
/* If the breakpoint lives in memory and reading that memory would
give back the breakpoint, instead of the original contents, then
the original contents are cached here. Only SHADOW_LEN bytes of
@@ -246,6 +251,25 @@ struct bp_location
different locations. */
struct expression *cond;

+ /* Flag to indicate if the condition is going to be accelerated
+ by hardware. If its value is non-zero, then GDB checks the
+ condition using hardware acceleration; otherwise it uses the
+ regular software-based checking. */
+ int cond_hw_accel : 1;
+
+ /* If the condition can be hardware-accelerated, then we must
+ get the condition's variable address so that GDB can
+ properly set the evaluation via hardware. */
+ CORE_ADDR cond_hw_addr;
+
+ /* If we are inserting a ranged hardware breakpoint, then we must
+ set its length here. */
+ ULONGEST ranged_hw_bp_length;
+
+ /* The mask address for this hardware watchpoint. It is valid only
+ if `hw_wp_use_mask' is 1. */
+ CORE_ADDR hw_wp_mask;
+
/* This location's address is in an unloaded solib, and so this
location should not be inserted. It will be automatically
enabled when that solib is loaded. */
@@ -373,6 +397,16 @@ DEF_VEC_I(int);
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);

+/* Special flags for hardware breakpoints/watchpoints. */
+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. */
+};
+
/* Note that the ->silent field is not currently used by any commands
(though the code is in there if it was to be, and set_raw_breakpoint
does set it to 0). I implemented it because I thought it would be
@@ -512,6 +546,9 @@ struct breakpoint

/* Chain of action lines to execute when this tracepoint is hit. */
struct action_line *actions;
+
+ /* Special flags. */
+ enum hw_point_flag hw_point_flag;
};

typedef struct breakpoint *breakpoint_p;
@@ -992,4 +1029,20 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
is newly allocated; the caller should free when done with it. */
extern VEC(breakpoint_p) *all_tracepoints (void);

+/* Return greater than zero if the condition associated with
+ the watchpoint `b' can be treated by the hardware; zero otherwise.
+
+ Also stores the data value in `data_value'. */
+extern int default_watch_address_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
+extern int default_watch_var_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
+extern int default_watch_address_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
+extern int default_watch_var_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
#endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index 1d28914..85f229c 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -45,6 +45,75 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
}
}

+/* Reads an address range, in one of the following formats:
+
+ start-address, end-address
+ start-address, +length
+
+ ARGS will be set to the first character after the end-address or length,
+ or if that character is a comma, the character following it. If a parser
+ error occurs, an exception is thrown and none of the arguments is
+ touched. */
+
+void
+parse_addr_range (char **args, CORE_ADDR *start_addrp,
+ ULONGEST *search_space_lenp)
+{
+ char *s = *args;
+ CORE_ADDR start_addr;
+ ULONGEST search_space_len;
+ struct value *v;
+
+ v = parse_to_comma_and_eval (&s);
+ start_addr = value_as_address (v);
+
+ if (*s == ',')
+ ++s;
+ while (isspace (*s))
+ ++s;
+
+ if (*s == '+')
+ {
+ LONGEST len;
+ ++s;
+ v = parse_to_comma_and_eval (&s);
+ len = value_as_long (v);
+
+ if (len == 0)
+ error (_("Empty search range."));
+ else if (len < 0)
+ error (_("Invalid length."));
+ /* Watch for overflows. */
+ else if (len > CORE_ADDR_MAX
+ || (start_addr + len - 1) < start_addr)
+ error (_("Search space too large."));
+
+ search_space_len = len;
+ }
+ else
+ {
+ CORE_ADDR end_addr;
+
+ v = parse_to_comma_and_eval (&s);
+ end_addr = value_as_address (v);
+ if (start_addr > end_addr)
+ error (_("Invalid search space, end preceeds start."));
+ search_space_len = end_addr - start_addr + 1;
+ /* We don't support searching all of memory
+ (i.e. start=0, end = 0xff..ff).
+ Bail to avoid overflows later on. */
+ if (search_space_len == 0)
+ error (_("Overflow in address range computation, choose smaller range."));
+ }
+
+ if (*s == ',')
+ ++s;
+
+ *args = s;
+ *start_addrp = start_addr;
+ *search_space_lenp = search_space_len;
+}
+
/* Subroutine of find_command to simplify it.
Parse the arguments of the "find" command. */

@@ -114,51 +183,7 @@ parse_find_args (char *args, ULONGEST *max_countp,
}

/* Get the search range. */
-
- v = parse_to_comma_and_eval (&s);
- start_addr = value_as_address (v);
-
- if (*s == ',')
- ++s;
- while (isspace (*s))
- ++s;
-
- if (*s == '+')
- {
- LONGEST len;
- ++s;
- v = parse_to_comma_and_eval (&s);
- len = value_as_long (v);
- if (len == 0)
- {
- printf_filtered (_("Empty search range.\n"));
- return;
- }
- if (len < 0)
- error (_("Invalid length."));
- /* Watch for overflows. */
- if (len > CORE_ADDR_MAX
- || (start_addr + len - 1) < start_addr)
- error (_("Search space too large."));
- search_space_len = len;
- }
- else
- {
- CORE_ADDR end_addr;
- v = parse_to_comma_and_eval (&s);
- end_addr = value_as_address (v);
- if (start_addr > end_addr)
- error (_("Invalid search space, end preceeds start."));
- search_space_len = end_addr - start_addr + 1;
- /* We don't support searching all of memory
- (i.e. start=0, end = 0xff..ff).
- Bail to avoid overflows later on. */
- if (search_space_len == 0)
- error (_("Overflow in address range computation, choose smaller range."));
- }
-
- if (*s == ',')
- ++s;
+ parse_addr_range (&s, &start_addr, &search_space_len);

/* Fetch the search string. */

diff --git a/gdb/testsuite/gdb.base/watchpoint.c b/gdb/testsuite/gdb.base/watchpoint.c
index bba97fa..1e95400 100644
--- a/gdb/testsuite/gdb.base/watchpoint.c
+++ b/gdb/testsuite/gdb.base/watchpoint.c
@@ -30,7 +30,7 @@ int ival2 = -1;
int ival3 = -1;
int ival4 = -1;
int ival5 = -1;
-char buf[10];
+char buf[30];
struct foo
{
int val;
@@ -95,6 +95,7 @@ func3 ()
x = 1; /* second x assignment */
y = 1;
y = 2;
+ buf[26] = 3;
}

int
diff --git a/gdb/testsuite/gdb.base/watchpoint.exp b/gdb/testsuite/gdb.base/watchpoint.exp
index 9fee73b..ee55e76 100644
--- a/gdb/testsuite/gdb.base/watchpoint.exp
+++ b/gdb/testsuite/gdb.base/watchpoint.exp
@@ -678,6 +678,24 @@ proc test_inaccessible_watchpoint {} {
}
}

+proc test_watchpoint_in_big_blob {} {
+ global gdb_prompt
+
+ gdb_test "watch buf" ".*atchpoint \[0-9\]+: buf"
+ send_gdb "cont\n"
+ gdb_expect {
+ -re "Continuing.*\[Ww\]atchpoint.*buf.*Old value = .*$gdb_prompt $" {
+ pass "watchpoint on buf hit"
+ }
+ -re "Continuing.*$gdb_prompt $" {
+ fail "watchpoint on buf hit"
+ }
+ -re ".*$gdb_prompt $" { fail "watchpoint on buf hit" ; return }
+ timeout { fail "watchpoint on buf hit (timeout)" ; return }
+ eof { fail "watchpoint on buf hit (eof)" ; return }
+ }
+}
+
# Start with a fresh gdb.

gdb_exit
@@ -842,6 +860,8 @@ if [initialize] then {
}

test_watchpoint_and_breakpoint
+
+ test_watchpoint_in_big_blob
}

# Restore old timeout
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);

diff --git a/gdb/value.h b/gdb/value.h
index 993f05b..d9cf12d 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -521,6 +521,9 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr);

extern LONGEST parse_and_eval_long (char *exp);

+void parse_addr_range (char **args, CORE_ADDR *start_addrp,
+ ULONGEST *search_space_lenp);
+
extern void unop_promote (const struct language_defn *language,
struct gdbarch *gdbarch,
struct value **arg1);