* [PATCH 3/4] Support ranged and masked watchpoints
@ 2009-12-24 0:32 Thiago Jung Bauermann
2010-01-04 17:33 ` Thiago Jung Bauermann
0 siblings, 1 reply; 5+ messages in thread
From: Thiago Jung Bauermann @ 2009-12-24 0:32 UTC (permalink / raw)
To: gdb-patches; +Cc: Luis Machado, Matt Tyrlik
[-- Attachment #1: Type: text/plain, Size: 4615 bytes --]
Adds support for the following types of watchpoints:
* Range Hardware Watchpoints: Monitors accesses to an interval of data
addresses. For the 476, a single Range Hardware Watchpoint can be
used provided that no Simple/Mask watchpoints are being used.
Available GDB commands:
watch-range <address1>, <address2>
watch-range <address1>, +<length>
Similarly for awatch-range and rwatch-range.
Examples:
watch-range &i,&k
awatch-range 0xbffff8e8,0xbffff8f8
rwatch-range 0xbffff8e8,+8
* Mask Hardware Watchpoints: Monitors accesses to data addresses that
match a specific pattern. For the 476, a single Mask Hardware
Watchpoint can be used provided that no Simple/Range watchpoints are
being used. Due to the processor's design, the precise data address
of the watchpoint trigger is not available, so the user must check the
instruction that caused the trigger (usually at PC - 4) to obtain
such data address. With such data address in hand, it's possible to
tell if its contents have changed.
Available GDB commands:
watch <variable | address> mask <mask_value>
Similarly for awatch-range and rwatch-range.
Examples:
watch i mask 0xffffff00
awatch *0xbffff8e8 mask 0xffffff00
Since the Simple/Range/Mask Hardware Watchpoints share the same register
set, the allowed combinations are as follows:
- 2 Simple Hardware Watchpoints with/without data value check
- 1 Range Hardware Watchpoint
- 1 Mask Hardware Watchpoint
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
2009-12-23 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.
(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 triggering of a hardware masked
watchpoint.
(watchpoint_check): Handle the case of a hardware mased watchpoint
trigger.
(hw_watchpoint_used_count): Call to target-specific function
that will tell how many extra slots a hardware watchpoint needs.
(mention): Handle mentioning of 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 and ranged watchpoints.
(ppc_linux_insert_mask_watchpoint): New function.
(ppc_linux_remove_mask_watchpoint): New function.
(ppc_linux_insert_watchpoint): Handle ranged watchpoints.
(ppc_linux_remove_watchpoint): Handle ranged watchpoints.
(ppc_linux_hw_point_extra_slot_count): New function.
(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
to_remove_mask_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 and to_hw_point_extra_slot_count.
* target.h (struct target_ops <to_insert_mask_watchpoint>,
<to_remove_mask_watchpoint>, <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_hw_point_extra_slot_count): Ditto.
* value.h (parse_addr_range): Declare.
[-- Attachment #2: ppc476-watchpoints.diff --]
[-- Type: text/x-patch, Size: 44554 bytes --]
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c 2009-12-23 17:07:34.000000000 -0200
+++ gdb/gdb/breakpoint.c 2009-12-23 17:14:52.000000000 -0200
@@ -1059,6 +1059,8 @@ update_watchpoint (struct breakpoint *b,
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,18 @@ update_watchpoint (struct breakpoint *b,
if (!watchpoint_in_thread_scope (b))
return;
+ /* 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 array and
update_global_locations will eventually delete them and remove
breakpoints if needed. */
@@ -1262,6 +1276,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));
@@ -1492,7 +1513,12 @@ Note: automatically using hardware break
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_COND_HW_ACCEL)
val = target_insert_cond_accel_watchpoint (bpt->address,
bpt->length,
bpt->watchpoint_type,
@@ -2126,7 +2152,11 @@ remove_breakpoint_1 (struct bp_location
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);
@@ -2918,13 +2948,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;
@@ -2936,10 +2972,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;
@@ -2953,24 +2997,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 = ");
+ }
+ }
+ 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);
}
- watchpoint_value_print (b->val, stb->stream);
- ui_out_field_stream (uiout, "new", stb);
+
ui_out_text (uiout, "\n");
result = PRINT_UNKNOWN;
break;
@@ -3179,15 +3238,30 @@ watchpoints_triggered (struct target_wai
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;
@@ -3290,6 +3364,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. */
@@ -5821,10 +5900,15 @@ hw_watchpoint_used_count (enum bptype ty
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;
}
}
@@ -6041,6 +6125,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);
@@ -6049,6 +6137,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);
@@ -6057,6 +6149,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);
@@ -7121,74 +7217,143 @@ watch_command_1 (char *arg, int accessfl
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. */
+
+ /* 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--;
+
+ /* 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--;
+
+ end_tok = 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;
- /* 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;
-
- /* 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;
-
- /* 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;
-
- 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;
-
- 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 <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;
@@ -7240,6 +7405,11 @@ watch_command_1 (char *arg, int accessfl
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,
@@ -7254,7 +7424,14 @@ watch_command_1 (char *arg, int accessfl
/* 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);
@@ -7302,6 +7479,12 @@ watch_command_1 (char *arg, int accessfl
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
@@ -7387,21 +7570,25 @@ can_use_hardware_watchpoint (struct valu
/* 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;
}
}
}
@@ -7452,6 +7639,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 can't be watched. Either the target watchpoint resources\n\
+don't 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,
+ 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);
+}
+
\f
/* Helper routines for the until_command routine in infcmd.c. Here
@@ -10852,7 +11134,40 @@ inferior in all-stop mode, gdb behaves a
&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);
+
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h 2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/breakpoint.h 2009-12-23 17:14:52.000000000 -0200
@@ -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. */
};
Index: gdb/gdb/findcmd.c
===================================================================
--- gdb.orig/gdb/findcmd.c 2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/findcmd.c 2009-12-23 17:09:38.000000000 -0200
@@ -45,6 +45,75 @@ put_bits (bfd_uint64_t data, char *buf,
}
}
+/* 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 *m
}
/* 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. */
Index: gdb/gdb/i386-nat.c
===================================================================
--- gdb.orig/gdb/i386-nat.c 2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/i386-nat.c 2009-12-23 17:09:38.000000000 -0200
@@ -530,8 +530,8 @@ i386_remove_watchpoint (CORE_ADDR addr,
/* 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;
Index: gdb/gdb/ppc-linux-nat.c
===================================================================
--- gdb.orig/gdb/ppc-linux-nat.c 2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/ppc-linux-nat.c 2009-12-23 17:14:52.000000000 -0200
@@ -1461,6 +1461,10 @@ ppc_linux_can_use_special_hw_point_p (en
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. */
@@ -1472,7 +1476,7 @@ ppc_linux_can_use_special_hw_point_p (en
}
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)
@@ -1483,9 +1487,14 @@ ppc_linux_region_ok_for_hw_watchpoint (C
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 arbitrary lengths. This takes
+ two hardware watchpoints though. */
+ if (ppc_linux_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+ return is_big_blob ? 2 : 1;
+ 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
@@ -1677,6 +1686,65 @@ ppc_linux_remove_hw_breakpoint (struct g
t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+ CORE_ADDR mask)
+{
+ struct ppc_hw_breakpoint p;
+ uint32_t trigger;
+ 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;
+
+ HW_WATCH_RW_TRIGGER (trigger, rw);
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = trigger;
+ 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;
+ uint32_t trigger;
+ 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;
+
+ HW_WATCH_RW_TRIGGER (trigger, rw);
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = trigger;
+ 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)
{
@@ -1755,12 +1823,12 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
if (have_ptrace_new_debug_booke)
{
+ struct ppc_hw_breakpoint p;
+ uint32_t trigger;
+
if (len <= 4)
ALL_LWPS (lp, ptid)
{
- struct ppc_hw_breakpoint p;
- uint32_t trigger;
-
HW_WATCH_RW_TRIGGER (trigger, rw);
p.version = PPC_DEBUG_CURRENT_VERSION;
@@ -1773,6 +1841,21 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
booke_insert_point (&p, TIDGET (ptid));
}
+ else
+ ALL_LWPS (lp, ptid)
+ {
+ HW_WATCH_RW_TRIGGER (trigger, rw);
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = trigger;
+ 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;
+
+ booke_insert_point (&p, TIDGET (ptid));
+ }
ret = 0;
}
@@ -1834,12 +1917,12 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
if (have_ptrace_new_debug_booke)
{
+ struct ppc_hw_breakpoint p;
+ uint32_t trigger;
+
if (len <= 4)
ALL_LWPS (lp, ptid)
{
- struct ppc_hw_breakpoint p;
- uint32_t trigger;
-
HW_WATCH_RW_TRIGGER (trigger, rw);
p.version = PPC_DEBUG_CURRENT_VERSION;
@@ -1852,6 +1935,21 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
booke_remove_point (&p, TIDGET (ptid));
}
+ else
+ ALL_LWPS (lp, ptid)
+ {
+ HW_WATCH_RW_TRIGGER (trigger, rw);
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = trigger;
+ 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;
+
+ booke_remove_point (&p, TIDGET (ptid));
+ }
ret = 0;
}
@@ -2008,6 +2106,30 @@ ppc_linux_can_use_watchpoint_cond_accel_
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)
@@ -2240,11 +2362,14 @@ _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_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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c 2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/target.c 2009-12-23 17:09:38.000000000 -0200
@@ -53,7 +53,7 @@ static void default_terminal_info (char
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
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,8 @@ update_current_target (void)
INHERIT (to_remove_hw_breakpoint, t);
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_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 +637,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 +751,12 @@ update_current_target (void)
de_fault (to_remove_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 +773,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 +2630,7 @@ Can't determine the current address spac
}
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 +3160,11 @@ debug_to_can_use_hw_breakpoint (int type
}
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",
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h 2009-12-23 17:06:07.000000000 -0200
+++ gdb/gdb/target.h 2009-12-23 17:09:38.000000000 -0200
@@ -411,6 +411,8 @@ 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_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 +423,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 +1199,8 @@ extern char *normal_pid_to_str (ptid_t p
(*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 +1232,17 @@ extern char *normal_pid_to_str (ptid_t p
#define target_remove_watchpoint(addr, len, type) \
(*current_target.to_remove_watchpoint) (addr, len, type)
+/* 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 +1270,11 @@ extern char *normal_pid_to_str (ptid_t p
#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 ? \
Index: gdb/gdb/value.h
===================================================================
--- gdb.orig/gdb/value.h 2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/value.h 2009-12-23 17:09:38.000000000 -0200
@@ -521,6 +521,9 @@ extern CORE_ADDR parse_and_eval_address_
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);
Index: gdb/gdb/spu-multiarch.c
===================================================================
--- gdb.orig/gdb/spu-multiarch.c 2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/spu-multiarch.c 2009-12-23 17:09:38.000000000 -0200
@@ -121,7 +121,7 @@ spu_thread_architecture (struct target_o
/* 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)
@@ -132,7 +132,8 @@ spu_region_ok_for_hw_watchpoint (CORE_AD
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;
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 3/4] Support ranged and masked watchpoints
2009-12-24 0:32 [PATCH 3/4] Support ranged and masked watchpoints Thiago Jung Bauermann
@ 2010-01-04 17:33 ` Thiago Jung Bauermann
2010-01-12 11:00 ` Joel Brobecker
0 siblings, 1 reply; 5+ messages in thread
From: Thiago Jung Bauermann @ 2010-01-04 17:33 UTC (permalink / raw)
To: gdb-patches; +Cc: Luis Machado, Matt Tyrlik
[-- Attachment #1: Type: Text/Plain, Size: 3508 bytes --]
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.
[-- Attachment #2: ppc476-watchpoints.diff --]
[-- Type: text/x-patch, Size: 45957 bytes --]
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);
+}
+
\f
/* 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);
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 3/4] Support ranged and masked watchpoints
2010-01-04 17:33 ` Thiago Jung Bauermann
@ 2010-01-12 11:00 ` Joel Brobecker
2010-01-12 13:56 ` Luis Machado
0 siblings, 1 reply; 5+ messages in thread
From: Joel Brobecker @ 2010-01-12 11:00 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches, Luis Machado, Matt Tyrlik
> > Adds support for the following types of watchpoints:
[range watchpoints]
In this instance as well, I would like to see if we could push all
the logic to the target, by providing all the information the target
needs in order to make that decision.
One nice upside is that this will allow the target to use both range
watchpoint and condition hardware acceleration if the target allows it.
Or if it doesn't, not separating the two types of features with
separate target watchpoint_insert/remove routines allows the target
to choose which one makes most sense if a choice needs to be made.
What do you think?
--
Joel
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 3/4] Support ranged and masked watchpoints
2010-01-12 11:00 ` Joel Brobecker
@ 2010-01-12 13:56 ` Luis Machado
2010-01-12 18:06 ` Joel Brobecker
0 siblings, 1 reply; 5+ messages in thread
From: Luis Machado @ 2010-01-12 13:56 UTC (permalink / raw)
To: Joel Brobecker; +Cc: Thiago Jung Bauermann, gdb-patches, Matt Tyrlik
On Tue, 2010-01-12 at 14:59 +0400, Joel Brobecker wrote:
> > > Adds support for the following types of watchpoints:
> [range watchpoints]
>
> In this instance as well, I would like to see if we could push all
> the logic to the target, by providing all the information the target
> needs in order to make that decision.
>
> One nice upside is that this will allow the target to use both range
> watchpoint and condition hardware acceleration if the target allows it.
> Or if it doesn't, not separating the two types of features with
> separate target watchpoint_insert/remove routines allows the target
> to choose which one makes most sense if a choice needs to be made.
>
> What do you think?
>
The overall idea of pushing all the code that is closer to the target
somewhere more suitable sounds good to me. That way we can keep the
generic portion of GDB clean, which is less painful to maintain.
This would probably depend on the target vector facelift?
Regards,
Luis
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 3/4] Support ranged and masked watchpoints
2010-01-12 13:56 ` Luis Machado
@ 2010-01-12 18:06 ` Joel Brobecker
0 siblings, 0 replies; 5+ messages in thread
From: Joel Brobecker @ 2010-01-12 18:06 UTC (permalink / raw)
To: Luis Machado; +Cc: Thiago Jung Bauermann, gdb-patches, Matt Tyrlik
> This would probably depend on the target vector facelift?
Yes and no - I don't think it would be fair to refuse the feature
just because the current code is not optimal. This is why we should
try to find a compromise, where we don't make things worse, if we can.
It's not clear to me how to best balance everything, hence the rather
lengthy emails... (and perhaps the baby steps! ;-).
--
Joel
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-01-12 18:06 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-24 0:32 [PATCH 3/4] Support ranged and masked watchpoints Thiago Jung Bauermann
2010-01-04 17:33 ` Thiago Jung Bauermann
2010-01-12 11:00 ` Joel Brobecker
2010-01-12 13:56 ` Luis Machado
2010-01-12 18:06 ` Joel Brobecker
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox