2011-05-06 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>

Thiago Jung Bauermann  <bauerman@br.ibm.com>

	Implement support for PowerPC BookE masked watchpoints.

gdb/
	* NEWS: Mention masked watchpoint support.  Create "Changed commands"
	section.
	* breakpoint.h (struct breakpoint_ops) <works_in_software_mode>: New
	method.  Initialize to NULL in all existing breakpoint_ops instances.
	(struct breakpoint) <hw_wp_mask>: New field.
	* breakpoint.c (is_masked_watchpoint): Add prototype.
	(update_watchpoint): Don't set b->val for masked watchpoints.  Call
	breakpoint's breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Likewise.
	(works_in_software_mode_watchpoint): New function.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New
	functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Set b->ops according to the type of hardware watchpoint being created.
	* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
	(ppc_linux_remove_mask_watchpoint)
	(ppc_linux_masked_watch_num_registers): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint and to_masked_watch_num_registers.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, and to_masked_watch_num_registers.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): New functions.
	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
	methods.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): Add prototypes.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Mention support of masked watchpoints.
This commit is contained in:
Thiago Jung Bauermann 2011-05-06 18:46:33 +00:00
parent d472a4264b
commit 9c06b0b428
10 changed files with 617 additions and 72 deletions

View file

@ -1,3 +1,43 @@
2011-05-06 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Implement support for PowerPC BookE masked watchpoints.
* NEWS: Mention masked watchpoint support. Create "Changed commands"
section.
* breakpoint.h (struct breakpoint_ops) <works_in_software_mode>: New
method. Initialize to NULL in all existing breakpoint_ops instances.
(struct breakpoint) <hw_wp_mask>: New field.
* breakpoint.c (is_masked_watchpoint): Add prototype.
(update_watchpoint): Don't set b->val for masked watchpoints. Call
breakpoint's breakpoint_ops.works_in_software_mode if available.
(watchpoints_triggered): Handle the case of a hardware masked
watchpoint trigger.
(watchpoint_check): Likewise.
(works_in_software_mode_watchpoint): New function.
(insert_masked_watchpoint, remove_masked_watchpoint)
(resources_needed_masked_watchpoint)
(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
(print_recreate_masked_watchpoint, is_masked_watchpoint): New
functions.
(masked_watchpoint_breakpoint_ops): New structure.
(watch_command_1): Check for the existence of the `mask' parameter.
Set b->ops according to the type of hardware watchpoint being created.
* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
(ppc_linux_remove_mask_watchpoint)
(ppc_linux_masked_watch_num_registers): New functions.
(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
to_remove_mask_watchpoint and to_masked_watch_num_registers.
* target.c (update_current_target): Mention to_insert_mask_watchpoint,
to_remove_mask_watchpoint, and to_masked_watch_num_registers.
(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
(target_masked_watch_num_registers): New functions.
* target.h (struct target_ops) <to_insert_mask_watchpoint>,
<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
methods.
(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
(target_masked_watch_num_registers): Add prototypes.
2011-05-06 Jan Kratochvil <jan.kratochvil@redhat.com>
PR 12573

View file

@ -3,10 +3,24 @@
*** Changes since GDB 7.3
* When natively debugging programs on PowerPC BookE processors running
a Linux kernel version 2.6.34 or later, GDB supports masked hardware
watchpoints, which specify a mask in addition to an address to watch.
The mask specifies that some bits of an address (the bits which are
reset in the mask) should be ignored when matching the address accessed
by the inferior against the watchpoint address. See the "PowerPC Embedded"
section in the user manual for more details.
* The new option --once causes GDBserver to stop listening for connections once
the first connection is made. The listening port used by GDBserver will
become available after that.
* Changed commands
watch EXPRESSION mask MASK_VALUE
The watch command now supports the mask argument which allows creation
of masked watchpoints, if the current architecture supports this feature.
*** Changes in GDB 7.3
* GDB has a new command: "thread find [REGEXP]".

View file

@ -10950,6 +10950,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
NULL, /* remove */
NULL, /* breakpoint_hit */
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_catch_exception,
print_one_catch_exception,
NULL, /* print_one_detail */
@ -10990,6 +10991,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
NULL, /* remove */
NULL, /* breakpoint_hit */
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_catch_exception_unhandled,
print_one_catch_exception_unhandled,
NULL, /* print_one_detail */
@ -11028,6 +11030,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
NULL, /* remove */
NULL, /* breakpoint_hit */
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_catch_assert,
print_one_catch_assert,
NULL, /* print_one_detail */

View file

@ -224,6 +224,8 @@ static void disable_trace_command (char *, int);
static void trace_pass_command (char *, int);
static int is_masked_watchpoint (const struct breakpoint *b);
/* Assuming we're creating a static tracepoint, does S look like a
static tracepoint marker spec ("-m MARKER_ID")? */
#define is_marker_spec(s) \
@ -1345,8 +1347,10 @@ update_watchpoint (struct breakpoint *b, int reparse)
/* Avoid setting b->val if it's already set. The meaning of
b->val is 'the last value' user saw, and we should update
it only if we reported that last value to user. As it
happens, the code that reports it updates b->val directly. */
if (!b->val_valid)
happens, the code that reports it updates b->val directly.
We don't keep track of the memory value for masked
watchpoints. */
if (!b->val_valid && !is_masked_watchpoint (b))
{
b->val = v;
b->val_valid = 1;
@ -1435,19 +1439,23 @@ update_watchpoint (struct breakpoint *b, int reparse)
(b->type, i, other_type_used);
if (target_resources_ok <= 0)
{
if (target_resources_ok == 0
&& b->type != bp_hardware_watchpoint)
/* If there's no works_in_software_mode method, we
assume that the watchpoint works in software mode. */
int sw_mode = (!b->ops || !b->ops->works_in_software_mode
|| b->ops->works_in_software_mode (b));
if (target_resources_ok == 0 && !sw_mode)
error (_("Target does not support this type of "
"hardware watchpoint."));
else if (target_resources_ok < 0
&& b->type != bp_hardware_watchpoint)
error (_("Target can only support one kind "
"of HW watchpoint at a time."));
else if (target_resources_ok < 0 && !sw_mode)
error (_("There are not enough available hardware "
"resources for this watchpoint."));
else
b->type = bp_watchpoint;
}
}
else if (b->type != bp_hardware_watchpoint)
else if (b->ops && b->ops->works_in_software_mode
&& !b->ops->works_in_software_mode (b))
error (_("Expression cannot be implemented with "
"read/access watchpoint."));
else
@ -3694,15 +3702,27 @@ watchpoints_triggered (struct target_waitstatus *ws)
b->watchpoint_triggered = watch_triggered_no;
for (loc = b->loc; loc; loc = loc->next)
/* Exact match not required. Within range is
sufficient. */
if (target_watchpoint_addr_within_range (&current_target,
addr, loc->address,
loc->length))
{
b->watchpoint_triggered = watch_triggered_yes;
break;
}
{
if (is_masked_watchpoint (loc->owner))
{
CORE_ADDR newaddr = addr & loc->owner->hw_wp_mask;
CORE_ADDR start = loc->address & loc->owner->hw_wp_mask;
if (newaddr == start)
{
b->watchpoint_triggered = watch_triggered_yes;
break;
}
}
/* Exact match not required. Within range is sufficient. */
else if (target_watchpoint_addr_within_range (&current_target,
addr, loc->address,
loc->length))
{
b->watchpoint_triggered = watch_triggered_yes;
break;
}
}
}
return 1;
@ -3799,9 +3819,16 @@ watchpoint_check (void *p)
might be in the middle of evaluating a function call. */
int pc = 0;
struct value *mark = value_mark ();
struct value *mark;
struct value *new_val;
if (is_masked_watchpoint (b))
/* 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;
mark = value_mark ();
fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
/* We use value_equal_contents instead of value_equal because
@ -6303,6 +6330,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
remove_catch_fork,
breakpoint_hit_catch_fork,
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_catch_fork,
print_one_catch_fork,
NULL, /* print_one_detail */
@ -6401,6 +6429,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
remove_catch_vfork,
breakpoint_hit_catch_vfork,
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_catch_vfork,
print_one_catch_vfork,
NULL, /* print_one_detail */
@ -6688,6 +6717,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
remove_catch_syscall,
breakpoint_hit_catch_syscall,
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_catch_syscall,
print_one_catch_syscall,
NULL, /* print_one_detail */
@ -6845,6 +6875,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
remove_catch_exec,
breakpoint_hit_catch_exec,
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_catch_exec,
print_one_catch_exec,
NULL, /* print_one_detail */
@ -8470,6 +8501,7 @@ static struct breakpoint_ops ranged_breakpoint_ops =
NULL, /* remove */
breakpoint_hit_ranged_breakpoint,
resources_needed_ranged_breakpoint,
NULL, /* works_in_software_mode */
print_it_ranged_breakpoint,
print_one_ranged_breakpoint,
print_one_detail_ranged_breakpoint,
@ -8777,6 +8809,15 @@ resources_needed_watchpoint (const struct bp_location *bl)
return target_region_ok_for_hw_watchpoint (bl->address, length);
}
/* Implement the "works_in_software_mode" breakpoint_ops method for
hardware watchpoints. */
int
works_in_software_mode_watchpoint (const struct breakpoint *b)
{
return b->type == bp_hardware_watchpoint;
}
/* The breakpoint_ops structure to be used in hardware watchpoints. */
static struct breakpoint_ops watchpoint_breakpoint_ops =
@ -8785,6 +8826,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
remove_watchpoint,
NULL, /* breakpoint_hit */
resources_needed_watchpoint,
works_in_software_mode_watchpoint,
NULL, /* print_it */
NULL, /* print_one */
NULL, /* print_one_detail */
@ -8792,6 +8834,192 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
NULL /* print_recreate */
};
/* Implement the "insert" breakpoint_ops method for
masked hardware watchpoints. */
static int
insert_masked_watchpoint (struct bp_location *bl)
{
return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
bl->watchpoint_type);
}
/* Implement the "remove" breakpoint_ops method for
masked hardware watchpoints. */
static int
remove_masked_watchpoint (struct bp_location *bl)
{
return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
bl->watchpoint_type);
}
/* Implement the "resources_needed" breakpoint_ops method for
masked hardware watchpoints. */
static int
resources_needed_masked_watchpoint (const struct bp_location *bl)
{
return target_masked_watch_num_registers (bl->address,
bl->owner->hw_wp_mask);
}
/* Implement the "works_in_software_mode" breakpoint_ops method for
masked hardware watchpoints. */
static int
works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
{
return 0;
}
/* Implement the "print_it" breakpoint_ops method for
masked hardware watchpoints. */
static enum print_stop_action
print_it_masked_watchpoint (struct breakpoint *b)
{
/* Masked watchpoints have only one location. */
gdb_assert (b->loc && b->loc->next == NULL);
switch (b->type)
{
case bp_hardware_watchpoint:
annotate_watchpoint (b->number);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
break;
case bp_read_watchpoint:
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
break;
case bp_access_watchpoint:
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
break;
default:
internal_error (__FILE__, __LINE__,
_("Invalid hardware watchpoint type."));
}
mention (b);
ui_out_text (uiout, _("\n\
Check the underlying instruction at PC for the memory\n\
address and value which triggered this watchpoint.\n"));
ui_out_text (uiout, "\n");
/* More than one watchpoint may have been triggered. */
return PRINT_UNKNOWN;
}
/* Implement the "print_one_detail" breakpoint_ops method for
masked hardware watchpoints. */
static void
print_one_detail_masked_watchpoint (const struct breakpoint *b,
struct ui_out *uiout)
{
/* Masked watchpoints have only one location. */
gdb_assert (b->loc && b->loc->next == NULL);
ui_out_text (uiout, "\tmask ");
ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
ui_out_text (uiout, "\n");
}
/* Implement the "print_mention" breakpoint_ops method for
masked hardware watchpoints. */
static void
print_mention_masked_watchpoint (struct breakpoint *b)
{
struct cleanup *ui_out_chain;
switch (b->type)
{
case bp_hardware_watchpoint:
ui_out_text (uiout, "Masked hardware watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
break;
case bp_read_watchpoint:
ui_out_text (uiout, "Masked hardware read watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
break;
case bp_access_watchpoint:
ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
break;
default:
internal_error (__FILE__, __LINE__,
_("Invalid hardware watchpoint type."));
}
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
ui_out_field_string (uiout, "exp", b->exp_string);
do_cleanups (ui_out_chain);
}
/* Implement the "print_recreate" breakpoint_ops method for
masked hardware watchpoints. */
static void
print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
{
char tmp[40];
switch (b->type)
{
case bp_hardware_watchpoint:
fprintf_unfiltered (fp, "watch");
break;
case bp_read_watchpoint:
fprintf_unfiltered (fp, "rwatch");
break;
case bp_access_watchpoint:
fprintf_unfiltered (fp, "awatch");
break;
default:
internal_error (__FILE__, __LINE__,
_("Invalid hardware watchpoint type."));
}
sprintf_vma (tmp, b->hw_wp_mask);
fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
}
/* The breakpoint_ops structure to be used in masked hardware watchpoints. */
static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
{
insert_masked_watchpoint,
remove_masked_watchpoint,
NULL, /* breakpoint_hit */
resources_needed_masked_watchpoint,
works_in_software_mode_masked_watchpoint,
print_it_masked_watchpoint,
NULL, /* print_one */
print_one_detail_masked_watchpoint,
print_mention_masked_watchpoint,
print_recreate_masked_watchpoint
};
/* Tell whether the given watchpoint is a masked hardware watchpoint. */
static int
is_masked_watchpoint (const struct breakpoint *b)
{
return b->ops == &masked_watchpoint_breakpoint_ops;
}
/* accessflag: hw_write: watch write,
hw_read: watch read,
hw_access: watch access (read or write) */
@ -8807,73 +9035,97 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
struct frame_info *frame;
char *exp_start = NULL;
char *exp_end = NULL;
char *tok, *id_tok_start, *end_tok;
int toklen;
char *tok, *end_tok;
int toklen = -1;
char *cond_start = NULL;
char *cond_end = NULL;
enum bptype bp_type;
int thread = -1;
int pc = 0;
/* Flag to indicate whether we are going to use masks for
the hardware watchpoint. */
int use_mask = 0;
CORE_ADDR mask = 0;
/* Make sure that we actually have parameters to parse. */
if (arg != NULL && arg[0] != '\0')
{
toklen = strlen (arg); /* Size of argument list. */
char *value_start;
/* Points tok to the end of the argument list. */
tok = arg + toklen - 1;
/* Look for "parameter value" pairs at the end
of the arguments string. */
for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
{
/* Skip whitespace at the end of the argument list. */
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--;
/* Find the beginning of the last token.
This is the value of the parameter. */
while (tok > arg && (*tok != ' ' && *tok != '\t'))
tok--;
value_start = tok + 1;
/* Points end_tok to the beginning of the last token. */
id_tok_start = tok + 1;
/* Skip whitespace. */
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;
/* Find the beginning of the second to last token.
This is the parameter itself. */
while (tok > arg && (*tok != ' ' && *tok != '\t'))
tok--;
tok++;
toklen = end_tok - tok + 1;
while (tok > arg && (*tok != ' ' && *tok != '\t'))
tok--;
if (toklen == 6 && !strncmp (tok, "thread", 6))
{
/* 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;
/* Move the pointer forward to skip the whitespace and
calculate the length of the token. */
tok++;
toklen = end_tok - tok;
if (thread != -1)
error(_("You can specify only one thread."));
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 (value_start, &endp, 0);
/* 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."), value_start);
/* 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);
}
else if (toklen == 4 && !strncmp (tok, "mask", 4))
{
/* We've found a "mask" token, which means the user wants to
create a hardware watchpoint that is going to have the mask
facility. */
struct value *mask_value, *mark;
/* Check if the thread actually exists. */
if (!valid_thread_id (thread))
error (_("Unknown thread %d."), thread);
if (use_mask)
error(_("You can specify only one mask."));
/* 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';
}
use_mask = just_location = 1;
mark = value_mark ();
mask_value = parse_to_comma_and_eval (&value_start);
mask = value_as_address (mask_value);
value_free_to_mark (mark);
}
else
/* We didn't recognize what we found. We should stop here. */
break;
/* Truncate the string and get rid of the "parameter value" pair before
the arguments string is parsed by the parse_exp_1 function. */
*tok = '\0';
}
}
/* Parse the rest of the arguments. */
@ -8904,10 +9156,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
if (just_location)
{
int ret;
exp_valid_block = NULL;
val = value_addr (result);
release_value (val);
value_free_to_mark (mark);
if (use_mask)
{
ret = target_masked_watch_num_registers (value_as_address (val),
mask);
if (ret == -1)
error (_("This target does not support masked watchpoints."));
else if (ret == -2)
error (_("Invalid mask or memory region."));
}
}
else if (val != NULL)
release_value (val);
@ -9004,9 +9268,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
}
else
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
b->val_valid = 1;
b->ops = &watchpoint_breakpoint_ops;
if (use_mask)
{
b->hw_wp_mask = mask;
b->ops = &masked_watchpoint_breakpoint_ops;
}
else
{
b->val = val;
b->val_valid = 1;
b->ops = &watchpoint_breakpoint_ops;
}
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
@ -9543,6 +9816,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
NULL, /* remove */
NULL, /* breakpoint_hit */
NULL, /* resources_needed */
NULL, /* works_in_software_mode */
print_it_exception_catchpoint,
print_one_exception_catchpoint,
NULL, /* print_one_detail */

View file

@ -410,6 +410,11 @@ struct breakpoint_ops
the breakpoint or watchpoint needs one debug register. */
int (*resources_needed) (const struct bp_location *);
/* Tell whether we can downgrade from a hardware watchpoint to a software
one. If not, the user will not be able to enable the watchpoint when
there are not enough hardware resources available. */
int (*works_in_software_mode) (const struct breakpoint *);
/* The normal print routine for this breakpoint, called when we
hit it. */
enum print_stop_action (*print_it) (struct breakpoint *);
@ -651,6 +656,9 @@ struct breakpoint
/* Whether this watchpoint is exact (see target_exact_watchpoints). */
int exact;
/* The mask address for a masked hardware watchpoint. */
CORE_ADDR hw_wp_mask;
};
typedef struct breakpoint *breakpoint_p;

View file

@ -1,3 +1,10 @@
2011-05-06 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Implement support for PowerPC BookE masked watchpoints.
* gdb.texinfo (Set Watchpoints): Document mask parameter.
(PowerPC Embedded): Mention support of masked watchpoints.
2011-05-03 Joel Brobecker <brobecker@adacore.com>
* gdb.texinfo (In Memoriam): Replace litteral uses of `GDB' with

View file

@ -3725,7 +3725,7 @@ watchpoints, which do not slow down the running of your program.
@table @code
@kindex watch
@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
Set a watchpoint for an expression. @value{GDBN} will break when the
expression @var{expr} is written into by the program and its value
changes. The simplest (and the most popular) use of this command is
@ -3736,7 +3736,7 @@ to watch the value of a single variable:
@end smallexample
If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
clause, @value{GDBN} breaks only when the thread identified by
argument, @value{GDBN} breaks only when the thread identified by
@var{threadnum} changes the value of @var{expr}. If any other threads
change the value of @var{expr}, @value{GDBN} will not break. Note
that watchpoints restricted to a single thread in this way only work
@ -3751,13 +3751,30 @@ to determine the size of the watched memory. If the expression's
result does not have an address, then @value{GDBN} will print an
error.
The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
of masked watchpoints, if the current architecture supports this
feature (e.g., PowerPC Embedded architecture, see @ref{PowerPC
Embedded}.) A @dfn{masked watchpoint} specifies a mask in addition
to an address to watch. The mask specifies that some bits of an address
(the bits which are reset in the mask) should be ignored when matching
the address accessed by the inferior against the watchpoint address.
Thus, a masked watchpoint watches many addresses simultaneously---those
addresses whose unmasked bits are identical to the unmasked bits in the
watchpoint address. The @code{mask} argument implies @code{-location}.
Examples:
@smallexample
(@value{GDBP}) watch foo mask 0xffff00ff
(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
@end smallexample
@kindex rwatch
@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
Set a watchpoint that will break when the value of @var{expr} is read
by the program.
@kindex awatch
@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
Set a watchpoint that will break when @var{expr} is either read from
or written into by the program.
@ -18780,6 +18797,9 @@ region using one of the following commands (@pxref{Expressions}):
(@value{GDBP}) watch @{char[@var{length}]@} @var{address}
@end smallexample
PowerPC embedded processors support masked watchpoints. See the discussion
about the @code{mask} argument in @ref{Set Watchpoints}.
@cindex ranged breakpoint
PowerPC embedded processors support hardware accelerated
@dfn{ranged breakpoints}. A ranged breakpoint stops execution of

View file

@ -1739,6 +1739,64 @@ get_trigger_type (int rw)
return t;
}
/* Insert a new masked watchpoint at ADDR using the mask MASK.
RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
or hw_access for an access watchpoint. Returns 0 on success and throws
an error on failure. */
static int
ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
CORE_ADDR mask, int rw)
{
ptid_t ptid;
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
gdb_assert (have_ptrace_booke_interface ());
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 = addr;
p.addr2 = mask;
p.condition_value = 0;
ALL_LWPS (lp, ptid)
booke_insert_point (&p, TIDGET (ptid));
return 0;
}
/* Remove a masked watchpoint at ADDR with the mask MASK.
RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
or hw_access for an access watchpoint. Returns 0 on success and throws
an error on failure. */
static int
ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
CORE_ADDR mask, int rw)
{
ptid_t ptid;
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
gdb_assert (have_ptrace_booke_interface ());
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 = addr;
p.addr2 = mask;
p.condition_value = 0;
ALL_LWPS (lp, ptid)
booke_remove_point (&p, TIDGET (ptid));
return 0;
}
/* Check whether we have at least one free DVC register. */
static int
can_use_watchpoint_cond_accel (void)
@ -2224,6 +2282,26 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
return start <= addr + mask && start + length - 1 >= addr;
}
/* Return the number of registers needed for a masked hardware watchpoint. */
static int
ppc_linux_masked_watch_num_registers (struct target_ops *target,
CORE_ADDR addr, CORE_ADDR mask)
{
if (!have_ptrace_booke_interface ()
|| (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
return -1;
else if ((mask & 0xC0000000) != 0xC0000000)
{
warning (_("The given mask covers kernel address space "
"and cannot be used.\n"));
return -2;
}
else
return 2;
}
static void
ppc_linux_store_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
@ -2438,11 +2516,14 @@ _initialize_ppc_linux_nat (void)
t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
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_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_can_accel_watchpoint_condition
= ppc_linux_can_accel_watchpoint_condition;
t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
t->to_read_description = ppc_linux_read_description;

View file

@ -595,6 +595,8 @@ update_current_target (void)
/* Do not inherit to_ranged_break_num_registers. */
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
/* Do not inherit to_insert_mask_watchpoint. */
/* Do not inherit to_remove_mask_watchpoint. */
INHERIT (to_stopped_data_address, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
@ -602,6 +604,7 @@ update_current_target (void)
INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
INHERIT (to_can_accel_watchpoint_condition, t);
/* Do not inherit to_masked_watch_num_registers. */
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
INHERIT (to_terminal_ours_for_output, t);
@ -3518,6 +3521,75 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
tcomplain ();
}
/* The documentation for this function is in its prototype declaration in
target.h. */
int
target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_insert_mask_watchpoint != NULL)
{
int ret;
ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
if (targetdebug)
fprintf_unfiltered (gdb_stdlog, "\
target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
core_addr_to_string (addr),
core_addr_to_string (mask), rw, ret);
return ret;
}
return 1;
}
/* The documentation for this function is in its prototype declaration in
target.h. */
int
target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_remove_mask_watchpoint != NULL)
{
int ret;
ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
if (targetdebug)
fprintf_unfiltered (gdb_stdlog, "\
target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
core_addr_to_string (addr),
core_addr_to_string (mask), rw, ret);
return ret;
}
return 1;
}
/* The documentation for this function is in its prototype declaration
in target.h. */
int
target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_masked_watch_num_registers != NULL)
return t->to_masked_watch_num_registers (t, addr, mask);
return -1;
}
/* The documentation for this function is in its prototype declaration
in target.h. */

View file

@ -459,6 +459,10 @@ struct target_ops
int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
int (*to_insert_mask_watchpoint) (struct target_ops *,
CORE_ADDR, CORE_ADDR, int);
int (*to_remove_mask_watchpoint) (struct target_ops *,
CORE_ADDR, CORE_ADDR, int);
int (*to_stopped_by_watchpoint) (void);
int to_have_steppable_watchpoint;
int to_have_continuable_watchpoint;
@ -472,6 +476,8 @@ struct target_ops
int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
struct expression *);
int (*to_masked_watch_num_registers) (struct target_ops *,
CORE_ADDR, CORE_ADDR);
void (*to_terminal_init) (void);
void (*to_terminal_inferior) (void);
void (*to_terminal_ours_for_output) (void);
@ -1362,6 +1368,20 @@ extern char *target_thread_name (struct thread_info *);
#define target_remove_watchpoint(addr, len, type, cond) \
(*current_target.to_remove_watchpoint) (addr, len, type, cond)
/* Insert a new masked watchpoint at ADDR using the mask MASK.
RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
or hw_access for an access watchpoint. Returns 0 for success, 1 if
masked watchpoints are not supported, -1 for failure. */
extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
/* Remove a masked watchpoint at ADDR with the mask MASK.
RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
or hw_access for an access watchpoint. Returns 0 for success, non-zero
for failure. */
extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
#define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
(*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
@ -1395,6 +1415,12 @@ extern int target_ranged_break_num_registers (void);
#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
(*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
/* Return number of debug registers needed for a masked watchpoint,
-1 if masked watchpoints are not supported or -2 if the given address
and mask combination cannot be used. */
extern int target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask);
/* Target can execute in reverse? */
#define target_can_execute_reverse \
(current_target.to_can_execute_reverse ? \