aboutsummaryrefslogtreecommitdiff
path: root/gdb/breakpoint.c
diff options
context:
space:
mode:
authorThiago Jung Bauermann <bauerman@br.ibm.com>2011-05-06 18:46:33 +0000
committerThiago Jung Bauermann <bauerman@br.ibm.com>2011-05-06 18:46:33 +0000
commit9c06b0b4285bf0abffaa37bda5b4bf686691d805 (patch)
tree8dbb1651e667706adfca09deab5149071b392496 /gdb/breakpoint.c
parentd472a4264b2208644fad65766532806e01c5fba7 (diff)
downloadgdb-9c06b0b4285bf0abffaa37bda5b4bf686691d805.zip
gdb-9c06b0b4285bf0abffaa37bda5b4bf686691d805.tar.gz
gdb-9c06b0b4285bf0abffaa37bda5b4bf686691d805.tar.bz2
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.
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r--gdb/breakpoint.c418
1 files changed, 346 insertions, 72 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index b5fc448..e582c36 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -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--;
+
+ /* 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;
+
+ /* Skip whitespace. */
+ 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;
+
+ 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;
- /* 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--;
+ if (thread != -1)
+ error(_("You can specify only one thread."));
- /* Points end_tok to the beginning of the last token. */
- id_tok_start = tok + 1;
+ /* Extract the thread ID from the next token. */
+ thread = strtol (value_start, &endp, 0);
- /* 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--;
+ /* 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);
- end_tok = tok;
+ /* 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;
- while (tok > arg && (*tok != ' ' && *tok != '\t'))
- tok--;
+ if (use_mask)
+ error(_("You can specify only one mask."));
- /* Move the pointer forward to skip the whitespace and
- calculate the length of the token. */
- tok++;
- toklen = end_tok - tok;
+ use_mask = just_location = 1;
- 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';
- }
+ 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 */