This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH 3/4] Support ranged and masked watchpoints
- 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:20:36 -0200
- Subject: Re: [PATCH 3/4] Support ranged and masked watchpoints
- References: <200912232231.06331.bauerman@br.ibm.com>
On Wed 23 Dec 2009 22:31:06 Thiago Jung Bauermann wrote:
> Adds support for the following types of watchpoints:
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 (update_watchpoint): Add variables to save/restore
new fields for the new types of hardware breakpoints/watchpoints.
Call target_hw_point_extra_slot_count.
(insert_bp_location): Call the correct insertion method according
to the type of the hardware watchpoint.
(remove_breakpoint_1): Call the correct deletion method according
to the type of the hardware watchpoint.
(print_it_typical): Handle printing of masked watchpoints.
(watchpoints_triggered): Handle the case of a hardware masked
watchpoint trigger.
(watchpoint_check): Handle the case of a hardware masked watchpoint
trigger.
(hw_watchpoint_used_count): Call target-specific function that will
tell how many extra slots a hardware watchpoint needs.
(mention): Mention masked watchpoints.
(watch_command_1): Add a routine to check for the existence of the
`mask' parameter when the user creates a watchpoint.
(can_use_hardware_watchpoint): Add 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.
(_initialize_breakpoint): Register watch-range, awatch-range and
rwatch-range commands.
* breakpoint.h (struct bp_location) <ranged_hw_bp_length>,
<hw_wp_mask>: New fields.
(hw_point_flag) <HW_POINT_RANGED_WATCH>, <HW_POINT_MASKED_WATCH>: New values.
* findcmd.c (parse_addr_range): New function.
(parse_find_args): Call `parse_addr_range'.
* i386-nat.c (i386_region_ok_for_watchpoint): Add `is_big_blob'
parameter.
* spu-multiarch.c (spu_region_ok_for_hw_watchpoint): Ditto.
* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point_p): Handle
HW_POINT_RANGED_WATCH and HW_POINT_MASKED_WATCH cases.
(ppc_linux_region_ok_for_hw_watchpoint): Add the `is_big_blob'
parameter.
(ppc_linux_insert_mask_watchpoint): New function.
(ppc_linux_remove_mask_watchpoint): New function.
(ppc_linux_insert_ranged_watchpoint): New function.
(ppc_linux_remove_ranged_watchpoint): New function.
(ppc_linux_hw_point_extra_slot_count): New function.
(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
to_remove_ranged_watchpoint and hw_point_extra_slot_count.
* target.c (default_region_ok_for_hw_watchpoint): Add `is_big_blob'
parameter.
(debug_to_region_ok_for_hw_watchpoint): Ditto.
(update_current_target): Insert to_insert_mask_watchpoint,
to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
to_remove_ranged_watchpoint and to_hw_point_extra_slot_count.
* target.h (struct target_ops <to_insert_mask_watchpoint>,
<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
<to_remove_ranged_watchpoint> and <to_hw_point_extra_slot_count>): New
callbacks.
(target_region_ok_for_hw_watchpoint): Add `is_big_blob' parameter.
(target_insert_mask_watchpoint): New define.
(target_remove_mask_watchpoint): Ditto.
(target_insert_ranged_watchpoint): New define.
(target_remove_ranged_watchpoint): Ditto.
(target_hw_point_extra_slot_count): Ditto.
* value.h (parse_addr_range): Declare.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index cdd2997..66e0c8e 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1059,6 +1059,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,6 +1068,11 @@ update_watchpoint (struct breakpoint *b, int reparse)
if (!watchpoint_in_thread_scope (b))
return;
+ if (b->loc)
+ /* We've got to save the mask field before updating this watchpoint
+ (and consequently busting b->loc). */
+ mask = b->loc->hw_wp_mask;
+
/* We don't free locations. They are stored in bp_location array and
update_global_locations will eventually delete them and remove
breakpoints if needed. */
@@ -1167,8 +1174,11 @@ update_watchpoint (struct breakpoint *b, int reparse)
b->type = bp_watchpoint;
else
{
- int target_resources_ok = target_can_use_hardware_watchpoint
- (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+ int target_resources_ok;
+
+ mem_cnt += target_hw_point_extra_slot_count (b->hw_point_flag);
+ target_resources_ok = target_can_use_hardware_watchpoint
+ (bp_hardware_watchpoint, i + mem_cnt, other_type_used)
if (target_resources_ok <= 0)
b->type = bp_watchpoint;
else
@@ -1260,6 +1270,10 @@ in which its expression is valid.\n"),
b->disposition = disp_del_at_next_stop;
}
+ /* Restoring hw_wp_mask. */
+ if (b->loc)
+ b->loc->hw_wp_mask = mask;
+
/* Restore the selected frame. */
if (frame_saved)
select_frame (frame_find_by_id (saved_frame_id));
@@ -1490,7 +1504,16 @@ 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)
{
- if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ 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_RANGED_WATCH)
+ val = target_insert_ranged_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type);
+ 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,
@@ -2124,10 +2147,17 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
struct value *n;
b->inserted = (is == mark_inserted);
- if (b->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ 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 if (b->owner->hw_point_flag == HW_POINT_RANGED_WATCH)
+ val = target_remove_ranged_watchpoint (b->address, b->length,
+ b->watchpoint_type);
else
val = target_remove_watchpoint (b->address, b->length,
b->watchpoint_type);
@@ -2916,13 +2946,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;
@@ -2934,10 +2970,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;
@@ -2951,24 +2995,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;
@@ -3177,15 +3236,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 (¤t_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 (¤t_target,
+ newaddr, start,
+ loc->length))
+ {
+ b->watchpoint_triggered = watch_triggered_yes;
+ break;
+ }
+ }
}
return 1;
@@ -3295,6 +3369,11 @@ 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 know 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. */
@@ -5839,10 +5918,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;
}
}
@@ -6059,6 +6143,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);
@@ -6067,6 +6155,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);
@@ -6075,6 +6167,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);
@@ -7139,74 +7235,142 @@ 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;
+ /* Whether we are watching an array or struct and hence we will
+ try to use ranged hardware watchpoints, if available. */
+ int use_ranged = 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);
+
+ 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 <address>"
+ 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;
@@ -7258,6 +7422,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
error (_("Expression cannot be implemented with read/access watchpoint."));
if (mem_cnt != 0)
{
+ struct type *vtype = check_typedef (value_type (val));
+
+ /* 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);
+ /* If we are watching an array or struct, we may be able to do it using
+ a ranged watchpoint. */
+ else if ((TYPE_CODE (vtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (vtype) == TYPE_CODE_ARRAY)
+ && target_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+ {
+ use_ranged = 1;
+ mem_cnt += target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+ }
+
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
target_can_use_hardware_watchpoint (bp_type, i + mem_cnt,
@@ -7272,7 +7452,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);
@@ -7320,6 +7507,14 @@ 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;
+ }
+ else if (use_ranged)
+ b->hw_point_flag = HW_POINT_RANGED_WATCH;
+
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
@@ -7405,18 +7600,20 @@ 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));
- if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+ if (!target_region_ok_for_hw_watchpoint (vaddr, len,
+ is_big_blob))
return 0;
else
found_memory_cnt++;
@@ -7470,6 +7667,101 @@ 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", pulongest (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 cannot be watched. Either the target watchpoint resources\n\
+do not support it, or hardware watchpoints are disabled in GDB\n\
+(see \"set can-use-hw-watchpoints\")."));
+
+ 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 + 1,
+ other_type_used);
+ if (can_use_wp < 0)
+ error (_("Not enough hardware resources for specified watchpoint."));
+
+ 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);
+}
+
/* Helper routines for the until_command routine in infcmd.c. Here
@@ -10878,7 +11170,41 @@ 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 the [start-address, end-address] interval."));
+ 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 the\n\
+[start-address, end-address] interval."));
+ 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 the [start-address, end-address] interval."));
+ set_cmd_completer (c, expression_completer);
+
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index d0c52a9..48b6264 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -262,6 +262,14 @@ struct bp_location
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. */
@@ -392,6 +400,8 @@ 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_MASKED_WATCH, /* Hardware masked watchpoint. */
HW_POINT_COND_HW_ACCEL, /* Hardware watchpoint with condition
hardware-accelerated. */
};
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/i386-nat.c b/gdb/i386-nat.c
index edb78bf..d065c74 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -530,8 +530,8 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
/* Return non-zero if we can watch a memory region that starts at
address ADDR and whose length is LEN bytes. */
-static int
-i386_region_ok_for_watchpoint (CORE_ADDR addr, int len)
+int
+i386_region_ok_for_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
{
int nregs;
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 4697164..1d072e5 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1454,6 +1454,10 @@ ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
switch (flag)
{
+ case HW_POINT_RANGED_WATCH:
+ return features & PPC_DEBUG_FEATURE_DATA_BP_RANGE;
+ case HW_POINT_MASKED_WATCH:
+ return features & PPC_DEBUG_FEATURE_DATA_BP_MASK;
case HW_POINT_COND_HW_ACCEL:
return booke_debug_info.num_condition_regs > 0;
/* We also accept non-special *points. */
@@ -1465,7 +1469,7 @@ ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
}
static int
-ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
{
/* Handle sub-8-byte quantities. */
if (len <= 0)
@@ -1476,9 +1480,20 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
to determine the hardcoded watchable region for watchpoints. */
if (have_ptrace_new_debug_booke)
{
- if (booke_debug_info.data_bp_alignment
- && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
- + booke_debug_info.data_bp_alignment))
+ /* DAC-based processors (i.e., embedded processors), like the PowerPC 440
+ have ranged watchpoints and can watch any access within an arbitrary
+ memory region. This is useful to watch arrays and structs, for
+ instance. It takes two hardware watchpoints though. */
+ if (is_big_blob)
+ {
+ if (ppc_linux_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+ return 2;
+ else
+ return 0;
+ }
+ else if (booke_debug_info.data_bp_alignment
+ && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
+ + booke_debug_info.data_bp_alignment))
return 0;
}
/* addr+len must fall in the 8 byte watchable region for DABR-based
@@ -1675,6 +1690,59 @@ static int get_trigger_type (int rw)
}
static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+ CORE_ADDR mask)
+{
+ struct ppc_hw_breakpoint p;
+ unsigned long a = (unsigned long) addr,
+ m = (unsigned long) mask;
+ struct lwp_info *lp;
+ ptid_t ptid;
+
+ if (!have_ptrace_new_debug_booke)
+ return -1;
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.addr = (uint64_t) a;
+ p.addr2 = (uint64_t) m;
+ p.condition_value = 0;
+
+ ALL_LWPS (lp, ptid)
+ booke_insert_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
+ppc_linux_remove_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+ CORE_ADDR mask)
+{
+ struct ppc_hw_breakpoint p;
+ unsigned long a = (unsigned long) addr,
+ m = (unsigned long) mask;
+ struct lwp_info *lp;
+ ptid_t ptid;
+
+ if (!have_ptrace_new_debug_booke)
+ return -1;
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.addr = (uint64_t) a;
+ p.addr2 = (uint64_t) m;
+ p.condition_value = 0;
+
+ ALL_LWPS (lp, ptid)
+ booke_remove_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+static int
ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
CORE_ADDR cond)
{
@@ -1739,6 +1807,50 @@ ppc_linux_remove_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
}
static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+ struct lwp_info *lp;
+ ptid_t ptid;
+ int ret = -1;
+ struct ppc_hw_breakpoint p;
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.addr = (uint64_t) addr;
+ p.addr2 = (uint64_t) addr + len;
+ p.condition_value = 0;
+
+ ALL_LWPS (lp, ptid)
+ booke_insert_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
+ppc_linux_remove_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+ struct lwp_info *lp;
+ ptid_t ptid;
+ int ret = -1;
+ struct ppc_hw_breakpoint p;
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.addr = (uint64_t) addr;
+ p.addr2 = (uint64_t) addr + len;
+ p.condition_value = 0;
+
+ ALL_LWPS (lp, ptid)
+ booke_remove_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
{
struct lwp_info *lp;
@@ -1984,6 +2096,30 @@ ppc_linux_can_use_watchpoint_cond_accel_p (struct bp_location *b)
return ppc_linux_get_watchpoint_cond_accel_addr (b, &tmp_value);
}
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+ /* If this *point is a:
+
+ - Masked hardware watchpoint,
+ - Ranged hardware watchpoint
+
+ then it uses 1 extra slot. */
+ switch (flag)
+ {
+ case HW_POINT_MASKED_WATCH:
+ case HW_POINT_RANGED_WATCH:
+ return 1;
+ default:
+ return 0;
+ }
+
+ /* Otherwise, it is a normal *point and does not use
+ extra slots. */
+ return 0;
+}
+
+
static void
ppc_linux_store_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
@@ -2216,11 +2352,16 @@ _initialize_ppc_linux_nat (void)
ppc_linux_can_use_watchpoint_cond_accel_p;
t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+ t->to_insert_ranged_watchpoint = ppc_linux_insert_ranged_watchpoint;
+ t->to_remove_ranged_watchpoint = ppc_linux_remove_ranged_watchpoint;
+ t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+ t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
t->to_insert_cond_accel_watchpoint = ppc_linux_insert_cond_accel_watchpoint;
t->to_remove_cond_accel_watchpoint = ppc_linux_remove_cond_accel_watchpoint;
t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
t->to_stopped_data_address = ppc_linux_stopped_data_address;
t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
+ t->to_hw_point_extra_slot_count = ppc_linux_hw_point_extra_slot_count;
t->to_read_description = ppc_linux_read_description;
t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/spu-multiarch.c b/gdb/spu-multiarch.c
index cb6b305..87a8974 100644
--- a/gdb/spu-multiarch.c
+++ b/gdb/spu-multiarch.c
@@ -119,7 +119,7 @@ spu_thread_architecture (struct target_ops *ops, ptid_t ptid)
/* Override the to_region_ok_for_hw_watchpoint routine. */
static int
-spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
{
struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
while (ops_beneath && !ops_beneath->to_region_ok_for_hw_watchpoint)
@@ -130,7 +130,8 @@ spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
return 0;
if (ops_beneath)
- return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len);
+ return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len,
+ is_big_blob);
return 0;
}
diff --git a/gdb/target.c b/gdb/target.c
index 3b1476d..aff4822 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -53,7 +53,7 @@ static void default_terminal_info (char *, int);
static int default_watchpoint_addr_within_range (struct target_ops *,
CORE_ADDR, CORE_ADDR, int);
-static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int, int);
static int nosymbol (char *, CORE_ADDR *);
@@ -131,7 +131,7 @@ static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *);
static int debug_to_watchpoint_addr_within_range (struct target_ops *,
CORE_ADDR, CORE_ADDR, int);
-static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int, int);
static void debug_to_terminal_init (void);
@@ -626,6 +626,10 @@ update_current_target (void)
INHERIT (to_remove_hw_breakpoint, t);
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
+ INHERIT (to_insert_ranged_watchpoint, t);
+ INHERIT (to_remove_ranged_watchpoint, t);
+ INHERIT (to_insert_mask_watchpoint, t);
+ INHERIT (to_remove_mask_watchpoint, t);
INHERIT (to_insert_cond_accel_watchpoint, t);
INHERIT (to_remove_cond_accel_watchpoint, t);
INHERIT (to_get_watchpoint_cond_accel_addr, t);
@@ -635,6 +639,7 @@ update_current_target (void)
INHERIT (to_stopped_by_watchpoint, t);
INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
+ INHERIT (to_hw_point_extra_slot_count, t);
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
INHERIT (to_terminal_ours_for_output, t);
@@ -748,6 +753,18 @@ update_current_target (void)
de_fault (to_remove_watchpoint,
(int (*) (CORE_ADDR, int, int))
return_minus_one);
+ de_fault (to_insert_ranged_watchpoint,
+ (int (*) (CORE_ADDR, int, int))
+ return_minus_one);
+ de_fault (to_remove_ranged_watchpoint,
+ (int (*) (CORE_ADDR, int, int))
+ return_minus_one);
+ de_fault (to_insert_mask_watchpoint,
+ (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+ return_minus_one);
+ de_fault (to_remove_mask_watchpoint,
+ (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+ return_minus_one);
de_fault (to_insert_cond_accel_watchpoint,
(int (*) (CORE_ADDR, int, int, CORE_ADDR))
return_minus_one);
@@ -764,6 +781,9 @@ update_current_target (void)
default_watchpoint_addr_within_range);
de_fault (to_region_ok_for_hw_watchpoint,
default_region_ok_for_hw_watchpoint);
+ de_fault (to_hw_point_extra_slot_count,
+ (int (*) (enum hw_point_flag))
+ return_zero);
de_fault (to_get_watchpoint_cond_accel_addr,
(int (*) (struct bp_location *, CORE_ADDR *))
return_zero);
@@ -2618,7 +2638,7 @@ Can't determine the current address space of thread %s\n",
}
static int
-default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
{
return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT);
}
@@ -3148,11 +3168,11 @@ debug_to_can_use_hw_breakpoint (int type, int cnt, int from_tty)
}
static int
-debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
{
CORE_ADDR retval;
- retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len);
+ retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len, is_big_blob);
fprintf_unfiltered (gdb_stdlog,
"target_region_ok_for_hw_watchpoint (%ld, %ld) = 0x%lx\n",
diff --git a/gdb/target.h b/gdb/target.h
index c604846..f53e655 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -411,6 +411,10 @@ struct target_ops
int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_watchpoint) (CORE_ADDR, int, int);
int (*to_insert_watchpoint) (CORE_ADDR, int, int);
+ int (*to_insert_ranged_watchpoint) (CORE_ADDR, int, int);
+ int (*to_remove_ranged_watchpoint) (CORE_ADDR, int, int);
+ int (*to_insert_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
+ int (*to_remove_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
int (*to_insert_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
int (*to_remove_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
int (*to_stopped_by_watchpoint) (void);
@@ -421,7 +425,8 @@ struct target_ops
CORE_ADDR, CORE_ADDR, int);
int (*to_get_watchpoint_cond_accel_addr) (struct bp_location *,
CORE_ADDR *);
- int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
+ int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int, int);
+ int (*to_hw_point_extra_slot_count) (enum hw_point_flag);
void (*to_terminal_init) (void);
void (*to_terminal_inferior) (void);
void (*to_terminal_ours_for_output) (void);
@@ -1196,8 +1201,8 @@ extern char *normal_pid_to_str (ptid_t ptid);
(*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE);
#ifndef target_region_ok_for_hw_watchpoint
-#define target_region_ok_for_hw_watchpoint(addr, len) \
- (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
+#define target_region_ok_for_hw_watchpoint(addr, len, is_big_blob) \
+ (*current_target.to_region_ok_for_hw_watchpoint) (addr, len, is_big_blob)
#endif
/* Returns non-zero if the target supports the special type of hardware
@@ -1229,6 +1234,28 @@ extern char *normal_pid_to_str (ptid_t ptid);
#define target_remove_watchpoint(addr, len, type) \
(*current_target.to_remove_watchpoint) (addr, len, type)
+/* Hardware ranged watchpoints. */
+#ifndef target_insert_ranged_watchpoint
+#define target_insert_ranged_watchpoint(addr, len, type) \
+ (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+#endif
+
+#ifndef target_remove_ranged_watchpoint
+#define target_remove_ranged_watchpoint(addr, len, type) \
+ (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+#endif
+
+/* Hardware watchpoints with a mask associated. */
+#ifndef target_insert_mask_watchpoint
+#define target_insert_mask_watchpoint(addr, len, type, mask) \
+ (*current_target.to_insert_mask_watchpoint) (addr, len, type, mask)
+#endif
+
+#ifndef target_remove_mask_watchpoint
+#define target_remove_mask_watchpoint(addr, len, type, mask) \
+ (*current_target.to_remove_mask_watchpoint) (addr, len, type, mask)
+#endif
+
/* Hardware watchpoint with a condition associated (to be
hardware-accelerated). */
#ifndef target_insert_cond_accel_watchpoint
@@ -1256,6 +1283,11 @@ extern char *normal_pid_to_str (ptid_t ptid);
#define target_watchpoint_addr_within_range(target, addr, start, length) \
(*target.to_watchpoint_addr_within_range) (target, addr, start, length)
+#ifndef target_hw_point_extra_slot_count
+#define target_hw_point_extra_slot_count(flag) \
+ (*current_target.to_hw_point_extra_slot_count) (flag)
+#endif
+
/* Target can execute in reverse? */
#define target_can_execute_reverse \
(current_target.to_can_execute_reverse ? \
diff --git a/gdb/value.h b/gdb/value.h
index c0acccd..efef318 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);