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:
parent
d472a4264b
commit
9c06b0b428
10 changed files with 617 additions and 72 deletions
|
@ -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>
|
2011-05-06 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||||
|
|
||||||
PR 12573
|
PR 12573
|
||||||
|
|
14
gdb/NEWS
14
gdb/NEWS
|
@ -3,10 +3,24 @@
|
||||||
|
|
||||||
*** Changes since GDB 7.3
|
*** 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 new option --once causes GDBserver to stop listening for connections once
|
||||||
the first connection is made. The listening port used by GDBserver will
|
the first connection is made. The listening port used by GDBserver will
|
||||||
become available after that.
|
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
|
*** Changes in GDB 7.3
|
||||||
|
|
||||||
* GDB has a new command: "thread find [REGEXP]".
|
* GDB has a new command: "thread find [REGEXP]".
|
||||||
|
|
|
@ -10950,6 +10950,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
|
||||||
NULL, /* remove */
|
NULL, /* remove */
|
||||||
NULL, /* breakpoint_hit */
|
NULL, /* breakpoint_hit */
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_catch_exception,
|
print_it_catch_exception,
|
||||||
print_one_catch_exception,
|
print_one_catch_exception,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
@ -10990,6 +10991,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
|
||||||
NULL, /* remove */
|
NULL, /* remove */
|
||||||
NULL, /* breakpoint_hit */
|
NULL, /* breakpoint_hit */
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_catch_exception_unhandled,
|
print_it_catch_exception_unhandled,
|
||||||
print_one_catch_exception_unhandled,
|
print_one_catch_exception_unhandled,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
@ -11028,6 +11030,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
|
||||||
NULL, /* remove */
|
NULL, /* remove */
|
||||||
NULL, /* breakpoint_hit */
|
NULL, /* breakpoint_hit */
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_catch_assert,
|
print_it_catch_assert,
|
||||||
print_one_catch_assert,
|
print_one_catch_assert,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
|
410
gdb/breakpoint.c
410
gdb/breakpoint.c
|
@ -224,6 +224,8 @@ static void disable_trace_command (char *, int);
|
||||||
|
|
||||||
static void trace_pass_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
|
/* Assuming we're creating a static tracepoint, does S look like a
|
||||||
static tracepoint marker spec ("-m MARKER_ID")? */
|
static tracepoint marker spec ("-m MARKER_ID")? */
|
||||||
#define is_marker_spec(s) \
|
#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
|
/* Avoid setting b->val if it's already set. The meaning of
|
||||||
b->val is 'the last value' user saw, and we should update
|
b->val is 'the last value' user saw, and we should update
|
||||||
it only if we reported that last value to user. As it
|
it only if we reported that last value to user. As it
|
||||||
happens, the code that reports it updates b->val directly. */
|
happens, the code that reports it updates b->val directly.
|
||||||
if (!b->val_valid)
|
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 = v;
|
||||||
b->val_valid = 1;
|
b->val_valid = 1;
|
||||||
|
@ -1435,19 +1439,23 @@ update_watchpoint (struct breakpoint *b, int reparse)
|
||||||
(b->type, i, other_type_used);
|
(b->type, i, other_type_used);
|
||||||
if (target_resources_ok <= 0)
|
if (target_resources_ok <= 0)
|
||||||
{
|
{
|
||||||
if (target_resources_ok == 0
|
/* If there's no works_in_software_mode method, we
|
||||||
&& b->type != bp_hardware_watchpoint)
|
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 "
|
error (_("Target does not support this type of "
|
||||||
"hardware watchpoint."));
|
"hardware watchpoint."));
|
||||||
else if (target_resources_ok < 0
|
else if (target_resources_ok < 0 && !sw_mode)
|
||||||
&& b->type != bp_hardware_watchpoint)
|
error (_("There are not enough available hardware "
|
||||||
error (_("Target can only support one kind "
|
"resources for this watchpoint."));
|
||||||
"of HW watchpoint at a time."));
|
|
||||||
else
|
else
|
||||||
b->type = bp_watchpoint;
|
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 "
|
error (_("Expression cannot be implemented with "
|
||||||
"read/access watchpoint."));
|
"read/access watchpoint."));
|
||||||
else
|
else
|
||||||
|
@ -3694,15 +3702,27 @@ watchpoints_triggered (struct target_waitstatus *ws)
|
||||||
|
|
||||||
b->watchpoint_triggered = watch_triggered_no;
|
b->watchpoint_triggered = watch_triggered_no;
|
||||||
for (loc = b->loc; loc; loc = loc->next)
|
for (loc = b->loc; loc; loc = loc->next)
|
||||||
/* Exact match not required. Within range is
|
{
|
||||||
sufficient. */
|
if (is_masked_watchpoint (loc->owner))
|
||||||
if (target_watchpoint_addr_within_range (¤t_target,
|
{
|
||||||
addr, loc->address,
|
CORE_ADDR newaddr = addr & loc->owner->hw_wp_mask;
|
||||||
loc->length))
|
CORE_ADDR start = loc->address & loc->owner->hw_wp_mask;
|
||||||
{
|
|
||||||
b->watchpoint_triggered = watch_triggered_yes;
|
if (newaddr == start)
|
||||||
break;
|
{
|
||||||
}
|
b->watchpoint_triggered = watch_triggered_yes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Exact match not required. Within range is sufficient. */
|
||||||
|
else if (target_watchpoint_addr_within_range (¤t_target,
|
||||||
|
addr, loc->address,
|
||||||
|
loc->length))
|
||||||
|
{
|
||||||
|
b->watchpoint_triggered = watch_triggered_yes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -3799,9 +3819,16 @@ watchpoint_check (void *p)
|
||||||
might be in the middle of evaluating a function call. */
|
might be in the middle of evaluating a function call. */
|
||||||
|
|
||||||
int pc = 0;
|
int pc = 0;
|
||||||
struct value *mark = value_mark ();
|
struct value *mark;
|
||||||
struct value *new_val;
|
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);
|
fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
|
||||||
|
|
||||||
/* We use value_equal_contents instead of value_equal because
|
/* 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,
|
remove_catch_fork,
|
||||||
breakpoint_hit_catch_fork,
|
breakpoint_hit_catch_fork,
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_catch_fork,
|
print_it_catch_fork,
|
||||||
print_one_catch_fork,
|
print_one_catch_fork,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
@ -6401,6 +6429,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
|
||||||
remove_catch_vfork,
|
remove_catch_vfork,
|
||||||
breakpoint_hit_catch_vfork,
|
breakpoint_hit_catch_vfork,
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_catch_vfork,
|
print_it_catch_vfork,
|
||||||
print_one_catch_vfork,
|
print_one_catch_vfork,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
@ -6688,6 +6717,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
|
||||||
remove_catch_syscall,
|
remove_catch_syscall,
|
||||||
breakpoint_hit_catch_syscall,
|
breakpoint_hit_catch_syscall,
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_catch_syscall,
|
print_it_catch_syscall,
|
||||||
print_one_catch_syscall,
|
print_one_catch_syscall,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
@ -6845,6 +6875,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
|
||||||
remove_catch_exec,
|
remove_catch_exec,
|
||||||
breakpoint_hit_catch_exec,
|
breakpoint_hit_catch_exec,
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_catch_exec,
|
print_it_catch_exec,
|
||||||
print_one_catch_exec,
|
print_one_catch_exec,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
@ -8470,6 +8501,7 @@ static struct breakpoint_ops ranged_breakpoint_ops =
|
||||||
NULL, /* remove */
|
NULL, /* remove */
|
||||||
breakpoint_hit_ranged_breakpoint,
|
breakpoint_hit_ranged_breakpoint,
|
||||||
resources_needed_ranged_breakpoint,
|
resources_needed_ranged_breakpoint,
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_ranged_breakpoint,
|
print_it_ranged_breakpoint,
|
||||||
print_one_ranged_breakpoint,
|
print_one_ranged_breakpoint,
|
||||||
print_one_detail_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);
|
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. */
|
/* The breakpoint_ops structure to be used in hardware watchpoints. */
|
||||||
|
|
||||||
static struct breakpoint_ops watchpoint_breakpoint_ops =
|
static struct breakpoint_ops watchpoint_breakpoint_ops =
|
||||||
|
@ -8785,6 +8826,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
|
||||||
remove_watchpoint,
|
remove_watchpoint,
|
||||||
NULL, /* breakpoint_hit */
|
NULL, /* breakpoint_hit */
|
||||||
resources_needed_watchpoint,
|
resources_needed_watchpoint,
|
||||||
|
works_in_software_mode_watchpoint,
|
||||||
NULL, /* print_it */
|
NULL, /* print_it */
|
||||||
NULL, /* print_one */
|
NULL, /* print_one */
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
@ -8792,6 +8834,192 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
|
||||||
NULL /* print_recreate */
|
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,
|
/* accessflag: hw_write: watch write,
|
||||||
hw_read: watch read,
|
hw_read: watch read,
|
||||||
hw_access: watch access (read or write) */
|
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;
|
struct frame_info *frame;
|
||||||
char *exp_start = NULL;
|
char *exp_start = NULL;
|
||||||
char *exp_end = NULL;
|
char *exp_end = NULL;
|
||||||
char *tok, *id_tok_start, *end_tok;
|
char *tok, *end_tok;
|
||||||
int toklen;
|
int toklen = -1;
|
||||||
char *cond_start = NULL;
|
char *cond_start = NULL;
|
||||||
char *cond_end = NULL;
|
char *cond_end = NULL;
|
||||||
enum bptype bp_type;
|
enum bptype bp_type;
|
||||||
int thread = -1;
|
int thread = -1;
|
||||||
int pc = 0;
|
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. */
|
/* Make sure that we actually have parameters to parse. */
|
||||||
if (arg != NULL && arg[0] != '\0')
|
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. */
|
/* Look for "parameter value" pairs at the end
|
||||||
tok = arg + toklen - 1;
|
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
|
/* Find the beginning of the last token.
|
||||||
parameter. If we're expecting a 'thread <thread_num>'
|
This is the value of the parameter. */
|
||||||
parameter, this should be the thread identifier. */
|
while (tok > arg && (*tok != ' ' && *tok != '\t'))
|
||||||
while (tok > arg && (*tok == ' ' || *tok == '\t'))
|
tok--;
|
||||||
tok--;
|
value_start = tok + 1;
|
||||||
while (tok > arg && (*tok != ' ' && *tok != '\t'))
|
|
||||||
tok--;
|
|
||||||
|
|
||||||
/* Points end_tok to the beginning of the last token. */
|
/* Skip whitespace. */
|
||||||
id_tok_start = tok + 1;
|
while (tok > arg && (*tok == ' ' || *tok == '\t'))
|
||||||
|
tok--;
|
||||||
|
|
||||||
/* Go backwards in the parameters list. Skip one more
|
end_tok = tok;
|
||||||
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;
|
/* 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'))
|
if (toklen == 6 && !strncmp (tok, "thread", 6))
|
||||||
tok--;
|
{
|
||||||
|
/* 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
|
if (thread != -1)
|
||||||
calculate the length of the token. */
|
error(_("You can specify only one thread."));
|
||||||
tok++;
|
|
||||||
toklen = end_tok - tok;
|
|
||||||
|
|
||||||
if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
|
/* Extract the thread ID from the next token. */
|
||||||
{
|
thread = strtol (value_start, &endp, 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. */
|
/* Check if the user provided a valid numeric value for the
|
||||||
thread = strtol (id_tok_start, &endp, 0);
|
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
|
/* Check if the thread actually exists. */
|
||||||
thread ID. */
|
if (!valid_thread_id (thread))
|
||||||
if (*endp != ' ' && *endp != '\t' && *endp != '\0')
|
error (_("Unknown thread %d."), thread);
|
||||||
error (_("Invalid thread ID specification %s."), id_tok_start);
|
}
|
||||||
|
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 (use_mask)
|
||||||
if (!valid_thread_id (thread))
|
error(_("You can specify only one mask."));
|
||||||
error (_("Unknown thread %d."), thread);
|
|
||||||
|
|
||||||
/* Truncate the string and get rid of the thread <thread_num>
|
use_mask = just_location = 1;
|
||||||
parameter before the parameter list is parsed by the
|
|
||||||
evaluate_expression() function. */
|
mark = value_mark ();
|
||||||
*tok = '\0';
|
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. */
|
/* Parse the rest of the arguments. */
|
||||||
|
@ -8904,10 +9156,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
|
||||||
|
|
||||||
if (just_location)
|
if (just_location)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
exp_valid_block = NULL;
|
exp_valid_block = NULL;
|
||||||
val = value_addr (result);
|
val = value_addr (result);
|
||||||
release_value (val);
|
release_value (val);
|
||||||
value_free_to_mark (mark);
|
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)
|
else if (val != NULL)
|
||||||
release_value (val);
|
release_value (val);
|
||||||
|
@ -9004,9 +9268,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
b->exp_string = savestring (exp_start, exp_end - exp_start);
|
b->exp_string = savestring (exp_start, exp_end - exp_start);
|
||||||
b->val = val;
|
|
||||||
b->val_valid = 1;
|
if (use_mask)
|
||||||
b->ops = &watchpoint_breakpoint_ops;
|
{
|
||||||
|
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)
|
if (cond_start)
|
||||||
b->cond_string = savestring (cond_start, cond_end - 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, /* remove */
|
||||||
NULL, /* breakpoint_hit */
|
NULL, /* breakpoint_hit */
|
||||||
NULL, /* resources_needed */
|
NULL, /* resources_needed */
|
||||||
|
NULL, /* works_in_software_mode */
|
||||||
print_it_exception_catchpoint,
|
print_it_exception_catchpoint,
|
||||||
print_one_exception_catchpoint,
|
print_one_exception_catchpoint,
|
||||||
NULL, /* print_one_detail */
|
NULL, /* print_one_detail */
|
||||||
|
|
|
@ -410,6 +410,11 @@ struct breakpoint_ops
|
||||||
the breakpoint or watchpoint needs one debug register. */
|
the breakpoint or watchpoint needs one debug register. */
|
||||||
int (*resources_needed) (const struct bp_location *);
|
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
|
/* The normal print routine for this breakpoint, called when we
|
||||||
hit it. */
|
hit it. */
|
||||||
enum print_stop_action (*print_it) (struct breakpoint *);
|
enum print_stop_action (*print_it) (struct breakpoint *);
|
||||||
|
@ -651,6 +656,9 @@ struct breakpoint
|
||||||
|
|
||||||
/* Whether this watchpoint is exact (see target_exact_watchpoints). */
|
/* Whether this watchpoint is exact (see target_exact_watchpoints). */
|
||||||
int exact;
|
int exact;
|
||||||
|
|
||||||
|
/* The mask address for a masked hardware watchpoint. */
|
||||||
|
CORE_ADDR hw_wp_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct breakpoint *breakpoint_p;
|
typedef struct breakpoint *breakpoint_p;
|
||||||
|
|
|
@ -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>
|
2011-05-03 Joel Brobecker <brobecker@adacore.com>
|
||||||
|
|
||||||
* gdb.texinfo (In Memoriam): Replace litteral uses of `GDB' with
|
* gdb.texinfo (In Memoriam): Replace litteral uses of `GDB' with
|
||||||
|
|
|
@ -3725,7 +3725,7 @@ watchpoints, which do not slow down the running of your program.
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@kindex watch
|
@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
|
Set a watchpoint for an expression. @value{GDBN} will break when the
|
||||||
expression @var{expr} is written into by the program and its value
|
expression @var{expr} is written into by the program and its value
|
||||||
changes. The simplest (and the most popular) use of this command is
|
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
|
@end smallexample
|
||||||
|
|
||||||
If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
|
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
|
@var{threadnum} changes the value of @var{expr}. If any other threads
|
||||||
change the value of @var{expr}, @value{GDBN} will not break. Note
|
change the value of @var{expr}, @value{GDBN} will not break. Note
|
||||||
that watchpoints restricted to a single thread in this way only work
|
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
|
result does not have an address, then @value{GDBN} will print an
|
||||||
error.
|
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
|
@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
|
Set a watchpoint that will break when the value of @var{expr} is read
|
||||||
by the program.
|
by the program.
|
||||||
|
|
||||||
@kindex awatch
|
@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
|
Set a watchpoint that will break when @var{expr} is either read from
|
||||||
or written into by the program.
|
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}
|
(@value{GDBP}) watch @{char[@var{length}]@} @var{address}
|
||||||
@end smallexample
|
@end smallexample
|
||||||
|
|
||||||
|
PowerPC embedded processors support masked watchpoints. See the discussion
|
||||||
|
about the @code{mask} argument in @ref{Set Watchpoints}.
|
||||||
|
|
||||||
@cindex ranged breakpoint
|
@cindex ranged breakpoint
|
||||||
PowerPC embedded processors support hardware accelerated
|
PowerPC embedded processors support hardware accelerated
|
||||||
@dfn{ranged breakpoints}. A ranged breakpoint stops execution of
|
@dfn{ranged breakpoints}. A ranged breakpoint stops execution of
|
||||||
|
|
|
@ -1739,6 +1739,64 @@ get_trigger_type (int rw)
|
||||||
return t;
|
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. */
|
/* Check whether we have at least one free DVC register. */
|
||||||
static int
|
static int
|
||||||
can_use_watchpoint_cond_accel (void)
|
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 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
|
static void
|
||||||
ppc_linux_store_inferior_registers (struct target_ops *ops,
|
ppc_linux_store_inferior_registers (struct target_ops *ops,
|
||||||
struct regcache *regcache, int regno)
|
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_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
|
||||||
t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
|
t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
|
||||||
t->to_remove_watchpoint = ppc_linux_remove_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_by_watchpoint = ppc_linux_stopped_by_watchpoint;
|
||||||
t->to_stopped_data_address = ppc_linux_stopped_data_address;
|
t->to_stopped_data_address = ppc_linux_stopped_data_address;
|
||||||
t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
|
t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
|
||||||
t->to_can_accel_watchpoint_condition
|
t->to_can_accel_watchpoint_condition
|
||||||
= ppc_linux_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_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
|
||||||
|
|
||||||
t->to_read_description = ppc_linux_read_description;
|
t->to_read_description = ppc_linux_read_description;
|
||||||
|
|
72
gdb/target.c
72
gdb/target.c
|
@ -595,6 +595,8 @@ update_current_target (void)
|
||||||
/* Do not inherit to_ranged_break_num_registers. */
|
/* Do not inherit to_ranged_break_num_registers. */
|
||||||
INHERIT (to_insert_watchpoint, t);
|
INHERIT (to_insert_watchpoint, t);
|
||||||
INHERIT (to_remove_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_stopped_data_address, t);
|
||||||
INHERIT (to_have_steppable_watchpoint, t);
|
INHERIT (to_have_steppable_watchpoint, t);
|
||||||
INHERIT (to_have_continuable_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_watchpoint_addr_within_range, t);
|
||||||
INHERIT (to_region_ok_for_hw_watchpoint, t);
|
INHERIT (to_region_ok_for_hw_watchpoint, t);
|
||||||
INHERIT (to_can_accel_watchpoint_condition, t);
|
INHERIT (to_can_accel_watchpoint_condition, t);
|
||||||
|
/* Do not inherit to_masked_watch_num_registers. */
|
||||||
INHERIT (to_terminal_init, t);
|
INHERIT (to_terminal_init, t);
|
||||||
INHERIT (to_terminal_inferior, t);
|
INHERIT (to_terminal_inferior, t);
|
||||||
INHERIT (to_terminal_ours_for_output, 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 ();
|
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
|
/* The documentation for this function is in its prototype declaration
|
||||||
in target.h. */
|
in target.h. */
|
||||||
|
|
||||||
|
|
26
gdb/target.h
26
gdb/target.h
|
@ -459,6 +459,10 @@ struct target_ops
|
||||||
int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
|
int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
|
||||||
int (*to_insert_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_stopped_by_watchpoint) (void);
|
||||||
int to_have_steppable_watchpoint;
|
int to_have_steppable_watchpoint;
|
||||||
int to_have_continuable_watchpoint;
|
int to_have_continuable_watchpoint;
|
||||||
|
@ -472,6 +476,8 @@ struct target_ops
|
||||||
|
|
||||||
int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
|
int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
|
||||||
struct expression *);
|
struct expression *);
|
||||||
|
int (*to_masked_watch_num_registers) (struct target_ops *,
|
||||||
|
CORE_ADDR, CORE_ADDR);
|
||||||
void (*to_terminal_init) (void);
|
void (*to_terminal_init) (void);
|
||||||
void (*to_terminal_inferior) (void);
|
void (*to_terminal_inferior) (void);
|
||||||
void (*to_terminal_ours_for_output) (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) \
|
#define target_remove_watchpoint(addr, len, type, cond) \
|
||||||
(*current_target.to_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) \
|
#define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
|
||||||
(*current_target.to_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) \
|
#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
|
||||||
(*current_target.to_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? */
|
/* Target can execute in reverse? */
|
||||||
#define target_can_execute_reverse \
|
#define target_can_execute_reverse \
|
||||||
(current_target.to_can_execute_reverse ? \
|
(current_target.to_can_execute_reverse ? \
|
||||||
|
|
Loading…
Reference in a new issue