| Index: gdb/breakpoint.c
|
| diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
|
| index 5a8c29ce28181a29c305775362e506bd4ce87dcb..78fffd34e9eb7233b75c67c29831444210b5617c 100644
|
| --- a/gdb/breakpoint.c
|
| +++ b/gdb/breakpoint.c
|
| @@ -56,16 +56,21 @@
|
| #include "memattr.h"
|
| #include "ada-lang.h"
|
| #include "top.h"
|
| -#include "wrapper.h"
|
| #include "valprint.h"
|
| #include "jit.h"
|
| #include "xml-syscall.h"
|
| #include "parser-defs.h"
|
| +#include "gdb_regex.h"
|
| +#include "probe.h"
|
| #include "cli/cli-utils.h"
|
| #include "continuations.h"
|
| #include "stack.h"
|
| #include "skip.h"
|
| -#include "record.h"
|
| +#include "gdb_regex.h"
|
| +#include "ax-gdb.h"
|
| +#include "dummy-frame.h"
|
| +
|
| +#include "format.h"
|
|
|
| /* readline include files */
|
| #include "readline/readline.h"
|
| @@ -83,6 +88,8 @@ static void enable_delete_command (char *, int);
|
|
|
| static void enable_once_command (char *, int);
|
|
|
| +static void enable_count_command (char *, int);
|
| +
|
| static void disable_command (char *, int);
|
|
|
| static void enable_command (char *, int);
|
| @@ -97,6 +104,23 @@ static int breakpoint_re_set_one (void *);
|
|
|
| static void breakpoint_re_set_default (struct breakpoint *);
|
|
|
| +static void create_sals_from_address_default (char **,
|
| + struct linespec_result *,
|
| + enum bptype, char *,
|
| + char **);
|
| +
|
| +static void create_breakpoints_sal_default (struct gdbarch *,
|
| + struct linespec_result *,
|
| + struct linespec_sals *,
|
| + char *, char *, enum bptype,
|
| + enum bpdisp, int, int,
|
| + int,
|
| + const struct breakpoint_ops *,
|
| + int, int, int, unsigned);
|
| +
|
| +static void decode_linespec_default (struct breakpoint *, char **,
|
| + struct symtabs_and_lines *);
|
| +
|
| static void clear_command (char *, int);
|
|
|
| static void catch_command (char *, int);
|
| @@ -190,7 +214,8 @@ static void hbreak_command (char *, int);
|
|
|
| static void thbreak_command (char *, int);
|
|
|
| -static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp);
|
| +static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp,
|
| + int count);
|
|
|
| static void stop_command (char *arg, int from_tty);
|
|
|
| @@ -238,10 +263,17 @@ 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) \
|
| - (s != NULL && strncmp (s, "-m", 2) == 0 && ((s)[2] == ' ' || (s)[2] == '\t'))
|
| +static struct bp_location **get_first_locp_gte_addr (CORE_ADDR address);
|
| +
|
| +/* Return 1 if B refers to a static tracepoint set by marker ("-m"), zero
|
| + otherwise. */
|
| +
|
| +static int strace_marker_p (struct breakpoint *b);
|
| +
|
| +static void init_catchpoint (struct breakpoint *b,
|
| + struct gdbarch *gdbarch, int tempflag,
|
| + char *cond_string,
|
| + const struct breakpoint_ops *ops);
|
|
|
| /* The abstract base class all breakpoint_ops structures inherit
|
| from. */
|
| @@ -258,10 +290,58 @@ static struct breakpoint_ops internal_breakpoint_ops;
|
| /* Momentary breakpoints class type. */
|
| static struct breakpoint_ops momentary_breakpoint_ops;
|
|
|
| +/* Momentary breakpoints for bp_longjmp and bp_exception class type. */
|
| +static struct breakpoint_ops longjmp_breakpoint_ops;
|
| +
|
| /* The breakpoint_ops structure to be used in regular user created
|
| breakpoints. */
|
| struct breakpoint_ops bkpt_breakpoint_ops;
|
|
|
| +/* Breakpoints set on probes. */
|
| +static struct breakpoint_ops bkpt_probe_breakpoint_ops;
|
| +
|
| +/* Dynamic printf class type. */
|
| +static struct breakpoint_ops dprintf_breakpoint_ops;
|
| +
|
| +/* The style in which to perform a dynamic printf. This is a user
|
| + option because different output options have different tradeoffs;
|
| + if GDB does the printing, there is better error handling if there
|
| + is a problem with any of the arguments, but using an inferior
|
| + function lets you have special-purpose printers and sending of
|
| + output to the same place as compiled-in print functions. */
|
| +
|
| +static const char dprintf_style_gdb[] = "gdb";
|
| +static const char dprintf_style_call[] = "call";
|
| +static const char dprintf_style_agent[] = "agent";
|
| +static const char *const dprintf_style_enums[] = {
|
| + dprintf_style_gdb,
|
| + dprintf_style_call,
|
| + dprintf_style_agent,
|
| + NULL
|
| +};
|
| +static const char *dprintf_style = dprintf_style_gdb;
|
| +
|
| +/* The function to use for dynamic printf if the preferred style is to
|
| + call into the inferior. The value is simply a string that is
|
| + copied into the command, so it can be anything that GDB can
|
| + evaluate to a callable address, not necessarily a function name. */
|
| +
|
| +static char *dprintf_function = "";
|
| +
|
| +/* The channel to use for dynamic printf if the preferred style is to
|
| + call into the inferior; if a nonempty string, it will be passed to
|
| + the call as the first argument, with the format string as the
|
| + second. As with the dprintf function, this can be anything that
|
| + GDB knows how to evaluate, so in addition to common choices like
|
| + "stderr", this could be an app-specific expression like
|
| + "mystreams[curlogger]". */
|
| +
|
| +static char *dprintf_channel = "";
|
| +
|
| +/* True if dprintf commands should continue to operate even if GDB
|
| + has disconnected. */
|
| +static int disconnected_dprintf = 1;
|
| +
|
| /* A reference-counted struct command_line. This lets multiple
|
| breakpoints share a single command list. */
|
| struct counted_command_line
|
| @@ -348,21 +428,13 @@ show_automatic_hardware_breakpoints (struct ui_file *file, int from_tty,
|
| will remove breakpoints upon stop. If auto, GDB will behave as ON
|
| if in non-stop mode, and as OFF if all-stop mode.*/
|
|
|
| -static const char always_inserted_auto[] = "auto";
|
| -static const char always_inserted_on[] = "on";
|
| -static const char always_inserted_off[] = "off";
|
| -static const char *always_inserted_enums[] = {
|
| - always_inserted_auto,
|
| - always_inserted_off,
|
| - always_inserted_on,
|
| - NULL
|
| -};
|
| -static const char *always_inserted_mode = always_inserted_auto;
|
| +static enum auto_boolean always_inserted_mode = AUTO_BOOLEAN_AUTO;
|
| +
|
| static void
|
| show_always_inserted_mode (struct ui_file *file, int from_tty,
|
| struct cmd_list_element *c, const char *value)
|
| {
|
| - if (always_inserted_mode == always_inserted_auto)
|
| + if (always_inserted_mode == AUTO_BOOLEAN_AUTO)
|
| fprintf_filtered (file,
|
| _("Always inserted breakpoint "
|
| "mode is %s (currently %s).\n"),
|
| @@ -376,9 +448,66 @@ show_always_inserted_mode (struct ui_file *file, int from_tty,
|
| int
|
| breakpoints_always_inserted_mode (void)
|
| {
|
| - return ((always_inserted_mode == always_inserted_on
|
| - || (always_inserted_mode == always_inserted_auto && non_stop))
|
| - && !RECORD_IS_USED);
|
| + return (always_inserted_mode == AUTO_BOOLEAN_TRUE
|
| + || (always_inserted_mode == AUTO_BOOLEAN_AUTO && non_stop));
|
| +}
|
| +
|
| +static const char condition_evaluation_both[] = "host or target";
|
| +
|
| +/* Modes for breakpoint condition evaluation. */
|
| +static const char condition_evaluation_auto[] = "auto";
|
| +static const char condition_evaluation_host[] = "host";
|
| +static const char condition_evaluation_target[] = "target";
|
| +static const char *const condition_evaluation_enums[] = {
|
| + condition_evaluation_auto,
|
| + condition_evaluation_host,
|
| + condition_evaluation_target,
|
| + NULL
|
| +};
|
| +
|
| +/* Global that holds the current mode for breakpoint condition evaluation. */
|
| +static const char *condition_evaluation_mode_1 = condition_evaluation_auto;
|
| +
|
| +/* Global that we use to display information to the user (gets its value from
|
| + condition_evaluation_mode_1. */
|
| +static const char *condition_evaluation_mode = condition_evaluation_auto;
|
| +
|
| +/* Translate a condition evaluation mode MODE into either "host"
|
| + or "target". This is used mostly to translate from "auto" to the
|
| + real setting that is being used. It returns the translated
|
| + evaluation mode. */
|
| +
|
| +static const char *
|
| +translate_condition_evaluation_mode (const char *mode)
|
| +{
|
| + if (mode == condition_evaluation_auto)
|
| + {
|
| + if (target_supports_evaluation_of_breakpoint_conditions ())
|
| + return condition_evaluation_target;
|
| + else
|
| + return condition_evaluation_host;
|
| + }
|
| + else
|
| + return mode;
|
| +}
|
| +
|
| +/* Discovers what condition_evaluation_auto translates to. */
|
| +
|
| +static const char *
|
| +breakpoint_condition_evaluation_mode (void)
|
| +{
|
| + return translate_condition_evaluation_mode (condition_evaluation_mode);
|
| +}
|
| +
|
| +/* Return true if GDB should evaluate breakpoint conditions or false
|
| + otherwise. */
|
| +
|
| +static int
|
| +gdb_evaluates_breakpoint_condition_p (void)
|
| +{
|
| + const char *mode = breakpoint_condition_evaluation_mode ();
|
| +
|
| + return (mode == condition_evaluation_host);
|
| }
|
|
|
| void _initialize_breakpoint (void);
|
| @@ -412,6 +541,20 @@ int target_exact_watchpoints = 0;
|
| BP_TMP < bp_location + bp_location_count && (B = *BP_TMP); \
|
| BP_TMP++)
|
|
|
| +/* Iterates through locations with address ADDRESS for the currently selected
|
| + program space. BP_LOCP_TMP points to each object. BP_LOCP_START points
|
| + to where the loop should start from.
|
| + If BP_LOCP_START is a NULL pointer, the macro automatically seeks the
|
| + appropriate location to start with. */
|
| +
|
| +#define ALL_BP_LOCATIONS_AT_ADDR(BP_LOCP_TMP, BP_LOCP_START, ADDRESS) \
|
| + for (BP_LOCP_START = BP_LOCP_START == NULL ? get_first_locp_gte_addr (ADDRESS) : BP_LOCP_START, \
|
| + BP_LOCP_TMP = BP_LOCP_START; \
|
| + BP_LOCP_START \
|
| + && (BP_LOCP_TMP < bp_location + bp_location_count \
|
| + && (*BP_LOCP_TMP)->address == ADDRESS); \
|
| + BP_LOCP_TMP++)
|
| +
|
| /* Iterator for tracepoints only. */
|
|
|
| #define ALL_TRACEPOINTS(B) \
|
| @@ -595,6 +738,178 @@ get_breakpoint (int num)
|
|
|
|
|
|
|
| +/* Mark locations as "conditions have changed" in case the target supports
|
| + evaluating conditions on its side. */
|
| +
|
| +static void
|
| +mark_breakpoint_modified (struct breakpoint *b)
|
| +{
|
| + struct bp_location *loc;
|
| +
|
| + /* This is only meaningful if the target is
|
| + evaluating conditions and if the user has
|
| + opted for condition evaluation on the target's
|
| + side. */
|
| + if (gdb_evaluates_breakpoint_condition_p ()
|
| + || !target_supports_evaluation_of_breakpoint_conditions ())
|
| + return;
|
| +
|
| + if (!is_breakpoint (b))
|
| + return;
|
| +
|
| + for (loc = b->loc; loc; loc = loc->next)
|
| + loc->condition_changed = condition_modified;
|
| +}
|
| +
|
| +/* Mark location as "conditions have changed" in case the target supports
|
| + evaluating conditions on its side. */
|
| +
|
| +static void
|
| +mark_breakpoint_location_modified (struct bp_location *loc)
|
| +{
|
| + /* This is only meaningful if the target is
|
| + evaluating conditions and if the user has
|
| + opted for condition evaluation on the target's
|
| + side. */
|
| + if (gdb_evaluates_breakpoint_condition_p ()
|
| + || !target_supports_evaluation_of_breakpoint_conditions ())
|
| +
|
| + return;
|
| +
|
| + if (!is_breakpoint (loc->owner))
|
| + return;
|
| +
|
| + loc->condition_changed = condition_modified;
|
| +}
|
| +
|
| +/* Sets the condition-evaluation mode using the static global
|
| + condition_evaluation_mode. */
|
| +
|
| +static void
|
| +set_condition_evaluation_mode (char *args, int from_tty,
|
| + struct cmd_list_element *c)
|
| +{
|
| + const char *old_mode, *new_mode;
|
| +
|
| + if ((condition_evaluation_mode_1 == condition_evaluation_target)
|
| + && !target_supports_evaluation_of_breakpoint_conditions ())
|
| + {
|
| + condition_evaluation_mode_1 = condition_evaluation_mode;
|
| + warning (_("Target does not support breakpoint condition evaluation.\n"
|
| + "Using host evaluation mode instead."));
|
| + return;
|
| + }
|
| +
|
| + new_mode = translate_condition_evaluation_mode (condition_evaluation_mode_1);
|
| + old_mode = translate_condition_evaluation_mode (condition_evaluation_mode);
|
| +
|
| + /* Flip the switch. Flip it even if OLD_MODE == NEW_MODE as one of the
|
| + settings was "auto". */
|
| + condition_evaluation_mode = condition_evaluation_mode_1;
|
| +
|
| + /* Only update the mode if the user picked a different one. */
|
| + if (new_mode != old_mode)
|
| + {
|
| + struct bp_location *loc, **loc_tmp;
|
| + /* If the user switched to a different evaluation mode, we
|
| + need to synch the changes with the target as follows:
|
| +
|
| + "host" -> "target": Send all (valid) conditions to the target.
|
| + "target" -> "host": Remove all the conditions from the target.
|
| + */
|
| +
|
| + if (new_mode == condition_evaluation_target)
|
| + {
|
| + /* Mark everything modified and synch conditions with the
|
| + target. */
|
| + ALL_BP_LOCATIONS (loc, loc_tmp)
|
| + mark_breakpoint_location_modified (loc);
|
| + }
|
| + else
|
| + {
|
| + /* Manually mark non-duplicate locations to synch conditions
|
| + with the target. We do this to remove all the conditions the
|
| + target knows about. */
|
| + ALL_BP_LOCATIONS (loc, loc_tmp)
|
| + if (is_breakpoint (loc->owner) && loc->inserted)
|
| + loc->needs_update = 1;
|
| + }
|
| +
|
| + /* Do the update. */
|
| + update_global_location_list (1);
|
| + }
|
| +
|
| + return;
|
| +}
|
| +
|
| +/* Shows the current mode of breakpoint condition evaluation. Explicitly shows
|
| + what "auto" is translating to. */
|
| +
|
| +static void
|
| +show_condition_evaluation_mode (struct ui_file *file, int from_tty,
|
| + struct cmd_list_element *c, const char *value)
|
| +{
|
| + if (condition_evaluation_mode == condition_evaluation_auto)
|
| + fprintf_filtered (file,
|
| + _("Breakpoint condition evaluation "
|
| + "mode is %s (currently %s).\n"),
|
| + value,
|
| + breakpoint_condition_evaluation_mode ());
|
| + else
|
| + fprintf_filtered (file, _("Breakpoint condition evaluation mode is %s.\n"),
|
| + value);
|
| +}
|
| +
|
| +/* A comparison function for bp_location AP and BP that is used by
|
| + bsearch. This comparison function only cares about addresses, unlike
|
| + the more general bp_location_compare function. */
|
| +
|
| +static int
|
| +bp_location_compare_addrs (const void *ap, const void *bp)
|
| +{
|
| + struct bp_location *a = *(void **) ap;
|
| + struct bp_location *b = *(void **) bp;
|
| +
|
| + if (a->address == b->address)
|
| + return 0;
|
| + else
|
| + return ((a->address > b->address) - (a->address < b->address));
|
| +}
|
| +
|
| +/* Helper function to skip all bp_locations with addresses
|
| + less than ADDRESS. It returns the first bp_location that
|
| + is greater than or equal to ADDRESS. If none is found, just
|
| + return NULL. */
|
| +
|
| +static struct bp_location **
|
| +get_first_locp_gte_addr (CORE_ADDR address)
|
| +{
|
| + struct bp_location dummy_loc;
|
| + struct bp_location *dummy_locp = &dummy_loc;
|
| + struct bp_location **locp_found = NULL;
|
| +
|
| + /* Initialize the dummy location's address field. */
|
| + memset (&dummy_loc, 0, sizeof (struct bp_location));
|
| + dummy_loc.address = address;
|
| +
|
| + /* Find a close match to the first location at ADDRESS. */
|
| + locp_found = bsearch (&dummy_locp, bp_location, bp_location_count,
|
| + sizeof (struct bp_location **),
|
| + bp_location_compare_addrs);
|
| +
|
| + /* Nothing was found, nothing left to do. */
|
| + if (locp_found == NULL)
|
| + return NULL;
|
| +
|
| + /* We may have found a location that is at ADDRESS but is not the first in the
|
| + location's list. Go backwards (if possible) and locate the first one. */
|
| + while ((locp_found - 1) >= bp_location
|
| + && (*(locp_found - 1))->address == address)
|
| + locp_found--;
|
| +
|
| + return locp_found;
|
| +}
|
| +
|
| void
|
| set_breakpoint_condition (struct breakpoint *b, char *exp,
|
| int from_tty)
|
| @@ -617,6 +932,10 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
|
| {
|
| xfree (loc->cond);
|
| loc->cond = NULL;
|
| +
|
| + /* No need to free the condition agent expression
|
| + bytecode (if we have one). We will handle this
|
| + when we go through update_global_location_list. */
|
| }
|
| }
|
|
|
| @@ -640,7 +959,7 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
|
|
|
| innermost_block = NULL;
|
| arg = exp;
|
| - w->cond_exp = parse_exp_1 (&arg, 0, 0);
|
| + w->cond_exp = parse_exp_1 (&arg, 0, 0, 0);
|
| if (*arg)
|
| error (_("Junk at end of expression"));
|
| w->cond_exp_valid_block = innermost_block;
|
| @@ -653,16 +972,75 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
|
| {
|
| arg = exp;
|
| loc->cond =
|
| - parse_exp_1 (&arg, block_for_pc (loc->address), 0);
|
| + parse_exp_1 (&arg, loc->address,
|
| + block_for_pc (loc->address), 0);
|
| if (*arg)
|
| error (_("Junk at end of expression"));
|
| }
|
| }
|
| }
|
| + mark_breakpoint_modified (b);
|
| +
|
| breakpoints_changed ();
|
| observer_notify_breakpoint_modified (b);
|
| }
|
|
|
| +/* Completion for the "condition" command. */
|
| +
|
| +static VEC (char_ptr) *
|
| +condition_completer (struct cmd_list_element *cmd, char *text, char *word)
|
| +{
|
| + char *space;
|
| +
|
| + text = skip_spaces (text);
|
| + space = skip_to_space (text);
|
| + if (*space == '\0')
|
| + {
|
| + int len;
|
| + struct breakpoint *b;
|
| + VEC (char_ptr) *result = NULL;
|
| +
|
| + if (text[0] == '$')
|
| + {
|
| + /* We don't support completion of history indices. */
|
| + if (isdigit (text[1]))
|
| + return NULL;
|
| + return complete_internalvar (&text[1]);
|
| + }
|
| +
|
| + /* We're completing the breakpoint number. */
|
| + len = strlen (text);
|
| +
|
| + ALL_BREAKPOINTS (b)
|
| + {
|
| + int single = b->loc->next == NULL;
|
| + struct bp_location *loc;
|
| + int count = 1;
|
| +
|
| + for (loc = b->loc; loc; loc = loc->next)
|
| + {
|
| + char location[50];
|
| +
|
| + if (single)
|
| + sprintf (location, "%d", b->number);
|
| + else
|
| + sprintf (location, "%d.%d", b->number, count);
|
| +
|
| + if (strncmp (location, text, len) == 0)
|
| + VEC_safe_push (char_ptr, result, xstrdup (location));
|
| +
|
| + ++count;
|
| + }
|
| + }
|
| +
|
| + return result;
|
| + }
|
| +
|
| + /* We're completing the expression part. */
|
| + text = skip_spaces (space);
|
| + return expression_completer (cmd, text, word);
|
| +}
|
| +
|
| /* condition N EXP -- set break condition of breakpoint N to EXP. */
|
|
|
| static void
|
| @@ -692,6 +1070,10 @@ condition_command (char *arg, int from_tty)
|
| error (_("Cannot set a condition where a Python 'stop' "
|
| "method has been defined in the breakpoint."));
|
| set_breakpoint_condition (b, p, from_tty);
|
| +
|
| + if (is_breakpoint (b))
|
| + update_global_location_list (1);
|
| +
|
| return;
|
| }
|
|
|
| @@ -1035,6 +1417,10 @@ bp_location_has_shadow (struct bp_location *bl)
|
| /* Update BUF, which is LEN bytes read from the target address MEMADDR,
|
| by replacing any memory breakpoints with their shadowed contents.
|
|
|
| + If READBUF is not NULL, this buffer must not overlap with any of
|
| + the breakpoint location's shadow_contents buffers. Otherwise,
|
| + a failed assertion internal error will be raised.
|
| +
|
| The range of shadowed area by each bp_location is:
|
| bl->address - bp_location_placed_address_before_address_max
|
| up to bl->address + bp_location_shadow_len_after_address_max
|
| @@ -1163,6 +1549,12 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
|
|
|
| if (readbuf != NULL)
|
| {
|
| + /* Verify that the readbuf buffer does not overlap with
|
| + the shadow_contents buffer. */
|
| + gdb_assert (bl->target_info.shadow_contents >= readbuf + len
|
| + || readbuf >= (bl->target_info.shadow_contents
|
| + + bl->target_info.shadow_len));
|
| +
|
| /* Update the read buffer with this inserted breakpoint's
|
| shadow. */
|
| memcpy (readbuf + bp_addr - memaddr,
|
| @@ -1191,6 +1583,17 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
|
| }
|
|
|
|
|
| +/* Return true if BPT is either a software breakpoint or a hardware
|
| + breakpoint. */
|
| +
|
| +int
|
| +is_breakpoint (const struct breakpoint *bpt)
|
| +{
|
| + return (bpt->type == bp_breakpoint
|
| + || bpt->type == bp_hardware_breakpoint
|
| + || bpt->type == bp_dprintf);
|
| +}
|
| +
|
| /* Return true if BPT is of any hardware watchpoint kind. */
|
|
|
| static int
|
| @@ -1223,9 +1626,10 @@ is_watchpoint (const struct breakpoint *bpt)
|
| static int
|
| watchpoint_in_thread_scope (struct watchpoint *b)
|
| {
|
| - return (ptid_equal (b->watchpoint_thread, null_ptid)
|
| - || (ptid_equal (inferior_ptid, b->watchpoint_thread)
|
| - && !is_executing (inferior_ptid)));
|
| + return (b->base.pspace == current_program_space
|
| + && (ptid_equal (b->watchpoint_thread, null_ptid)
|
| + || (ptid_equal (inferior_ptid, b->watchpoint_thread)
|
| + && !is_executing (inferior_ptid))));
|
| }
|
|
|
| /* Set watchpoint B to disp_del_at_next_stop, even including its possible
|
| @@ -1361,7 +1765,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
|
| b->exp = NULL;
|
| }
|
| s = b->exp_string_reparse ? b->exp_string_reparse : b->exp_string;
|
| - b->exp = parse_exp_1 (&s, b->exp_valid_block, 0);
|
| + b->exp = parse_exp_1 (&s, 0, b->exp_valid_block, 0);
|
| /* If the meaning of expression itself changed, the old value is
|
| no longer relevant. We don't want to report a watchpoint hit
|
| to the user when the old value and the new value may actually
|
| @@ -1382,7 +1786,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
|
| }
|
|
|
| s = b->base.cond_string;
|
| - b->cond_exp = parse_exp_1 (&s, b->cond_exp_valid_block, 0);
|
| + b->cond_exp = parse_exp_1 (&s, 0, b->cond_exp_valid_block, 0);
|
| }
|
| }
|
|
|
| @@ -1632,6 +2036,333 @@ unduplicated_should_be_inserted (struct bp_location *bl)
|
| return result;
|
| }
|
|
|
| +/* Parses a conditional described by an expression COND into an
|
| + agent expression bytecode suitable for evaluation
|
| + by the bytecode interpreter. Return NULL if there was
|
| + any error during parsing. */
|
| +
|
| +static struct agent_expr *
|
| +parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond)
|
| +{
|
| + struct agent_expr *aexpr = NULL;
|
| + struct cleanup *old_chain = NULL;
|
| + volatile struct gdb_exception ex;
|
| +
|
| + if (!cond)
|
| + return NULL;
|
| +
|
| + /* We don't want to stop processing, so catch any errors
|
| + that may show up. */
|
| + TRY_CATCH (ex, RETURN_MASK_ERROR)
|
| + {
|
| + aexpr = gen_eval_for_expr (scope, cond);
|
| + }
|
| +
|
| + if (ex.reason < 0)
|
| + {
|
| + /* If we got here, it means the condition could not be parsed to a valid
|
| + bytecode expression and thus can't be evaluated on the target's side.
|
| + It's no use iterating through the conditions. */
|
| + return NULL;
|
| + }
|
| +
|
| + /* We have a valid agent expression. */
|
| + return aexpr;
|
| +}
|
| +
|
| +/* Based on location BL, create a list of breakpoint conditions to be
|
| + passed on to the target. If we have duplicated locations with different
|
| + conditions, we will add such conditions to the list. The idea is that the
|
| + target will evaluate the list of conditions and will only notify GDB when
|
| + one of them is true. */
|
| +
|
| +static void
|
| +build_target_condition_list (struct bp_location *bl)
|
| +{
|
| + struct bp_location **locp = NULL, **loc2p;
|
| + int null_condition_or_parse_error = 0;
|
| + int modified = bl->needs_update;
|
| + struct bp_location *loc;
|
| +
|
| + /* This is only meaningful if the target is
|
| + evaluating conditions and if the user has
|
| + opted for condition evaluation on the target's
|
| + side. */
|
| + if (gdb_evaluates_breakpoint_condition_p ()
|
| + || !target_supports_evaluation_of_breakpoint_conditions ())
|
| + return;
|
| +
|
| + /* Do a first pass to check for locations with no assigned
|
| + conditions or conditions that fail to parse to a valid agent expression
|
| + bytecode. If any of these happen, then it's no use to send conditions
|
| + to the target since this location will always trigger and generate a
|
| + response back to GDB. */
|
| + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
|
| + {
|
| + loc = (*loc2p);
|
| + if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
|
| + {
|
| + if (modified)
|
| + {
|
| + struct agent_expr *aexpr;
|
| +
|
| + /* Re-parse the conditions since something changed. In that
|
| + case we already freed the condition bytecodes (see
|
| + force_breakpoint_reinsertion). We just
|
| + need to parse the condition to bytecodes again. */
|
| + aexpr = parse_cond_to_aexpr (bl->address, loc->cond);
|
| + loc->cond_bytecode = aexpr;
|
| +
|
| + /* Check if we managed to parse the conditional expression
|
| + correctly. If not, we will not send this condition
|
| + to the target. */
|
| + if (aexpr)
|
| + continue;
|
| + }
|
| +
|
| + /* If we have a NULL bytecode expression, it means something
|
| + went wrong or we have a null condition expression. */
|
| + if (!loc->cond_bytecode)
|
| + {
|
| + null_condition_or_parse_error = 1;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* If any of these happened, it means we will have to evaluate the conditions
|
| + for the location's address on gdb's side. It is no use keeping bytecodes
|
| + for all the other duplicate locations, thus we free all of them here.
|
| +
|
| + This is so we have a finer control over which locations' conditions are
|
| + being evaluated by GDB or the remote stub. */
|
| + if (null_condition_or_parse_error)
|
| + {
|
| + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
|
| + {
|
| + loc = (*loc2p);
|
| + if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
|
| + {
|
| + /* Only go as far as the first NULL bytecode is
|
| + located. */
|
| + if (!loc->cond_bytecode)
|
| + return;
|
| +
|
| + free_agent_expr (loc->cond_bytecode);
|
| + loc->cond_bytecode = NULL;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* No NULL conditions or failed bytecode generation. Build a condition list
|
| + for this location's address. */
|
| + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
|
| + {
|
| + loc = (*loc2p);
|
| + if (loc->cond
|
| + && is_breakpoint (loc->owner)
|
| + && loc->pspace->num == bl->pspace->num
|
| + && loc->owner->enable_state == bp_enabled
|
| + && loc->enabled)
|
| + /* Add the condition to the vector. This will be used later to send the
|
| + conditions to the target. */
|
| + VEC_safe_push (agent_expr_p, bl->target_info.conditions,
|
| + loc->cond_bytecode);
|
| + }
|
| +
|
| + return;
|
| +}
|
| +
|
| +/* Parses a command described by string CMD into an agent expression
|
| + bytecode suitable for evaluation by the bytecode interpreter.
|
| + Return NULL if there was any error during parsing. */
|
| +
|
| +static struct agent_expr *
|
| +parse_cmd_to_aexpr (CORE_ADDR scope, char *cmd)
|
| +{
|
| + struct cleanup *old_cleanups = 0;
|
| + struct expression *expr, **argvec;
|
| + struct agent_expr *aexpr = NULL;
|
| + struct cleanup *old_chain = NULL;
|
| + volatile struct gdb_exception ex;
|
| + char *cmdrest;
|
| + char *format_start, *format_end;
|
| + struct format_piece *fpieces;
|
| + int nargs;
|
| + struct gdbarch *gdbarch = get_current_arch ();
|
| +
|
| + if (!cmd)
|
| + return NULL;
|
| +
|
| + cmdrest = cmd;
|
| +
|
| + if (*cmdrest == ',')
|
| + ++cmdrest;
|
| + cmdrest = skip_spaces (cmdrest);
|
| +
|
| + if (*cmdrest++ != '"')
|
| + error (_("No format string following the location"));
|
| +
|
| + format_start = cmdrest;
|
| +
|
| + fpieces = parse_format_string (&cmdrest);
|
| +
|
| + old_cleanups = make_cleanup (free_format_pieces_cleanup, &fpieces);
|
| +
|
| + format_end = cmdrest;
|
| +
|
| + if (*cmdrest++ != '"')
|
| + error (_("Bad format string, non-terminated '\"'."));
|
| +
|
| + cmdrest = skip_spaces (cmdrest);
|
| +
|
| + if (!(*cmdrest == ',' || *cmdrest == '\0'))
|
| + error (_("Invalid argument syntax"));
|
| +
|
| + if (*cmdrest == ',')
|
| + cmdrest++;
|
| + cmdrest = skip_spaces (cmdrest);
|
| +
|
| + /* For each argument, make an expression. */
|
| +
|
| + argvec = (struct expression **) alloca (strlen (cmd)
|
| + * sizeof (struct expression *));
|
| +
|
| + nargs = 0;
|
| + while (*cmdrest != '\0')
|
| + {
|
| + char *cmd1;
|
| +
|
| + cmd1 = cmdrest;
|
| + expr = parse_exp_1 (&cmd1, scope, block_for_pc (scope), 1);
|
| + argvec[nargs++] = expr;
|
| + cmdrest = cmd1;
|
| + if (*cmdrest == ',')
|
| + ++cmdrest;
|
| + }
|
| +
|
| + /* We don't want to stop processing, so catch any errors
|
| + that may show up. */
|
| + TRY_CATCH (ex, RETURN_MASK_ERROR)
|
| + {
|
| + aexpr = gen_printf (scope, gdbarch, 0, 0,
|
| + format_start, format_end - format_start,
|
| + fpieces, nargs, argvec);
|
| + }
|
| +
|
| + if (ex.reason < 0)
|
| + {
|
| + /* If we got here, it means the command could not be parsed to a valid
|
| + bytecode expression and thus can't be evaluated on the target's side.
|
| + It's no use iterating through the other commands. */
|
| + return NULL;
|
| + }
|
| +
|
| + do_cleanups (old_cleanups);
|
| +
|
| + /* We have a valid agent expression, return it. */
|
| + return aexpr;
|
| +}
|
| +
|
| +/* Based on location BL, create a list of breakpoint commands to be
|
| + passed on to the target. If we have duplicated locations with
|
| + different commands, we will add any such to the list. */
|
| +
|
| +static void
|
| +build_target_command_list (struct bp_location *bl)
|
| +{
|
| + struct bp_location **locp = NULL, **loc2p;
|
| + int null_command_or_parse_error = 0;
|
| + int modified = bl->needs_update;
|
| + struct bp_location *loc;
|
| +
|
| + /* For now, limit to agent-style dprintf breakpoints. */
|
| + if (bl->owner->type != bp_dprintf
|
| + || strcmp (dprintf_style, dprintf_style_agent) != 0)
|
| + return;
|
| +
|
| + if (!target_can_run_breakpoint_commands ())
|
| + return;
|
| +
|
| + /* Do a first pass to check for locations with no assigned
|
| + conditions or conditions that fail to parse to a valid agent expression
|
| + bytecode. If any of these happen, then it's no use to send conditions
|
| + to the target since this location will always trigger and generate a
|
| + response back to GDB. */
|
| + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
|
| + {
|
| + loc = (*loc2p);
|
| + if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
|
| + {
|
| + if (modified)
|
| + {
|
| + struct agent_expr *aexpr;
|
| +
|
| + /* Re-parse the commands since something changed. In that
|
| + case we already freed the command bytecodes (see
|
| + force_breakpoint_reinsertion). We just
|
| + need to parse the command to bytecodes again. */
|
| + aexpr = parse_cmd_to_aexpr (bl->address,
|
| + loc->owner->extra_string);
|
| + loc->cmd_bytecode = aexpr;
|
| +
|
| + if (!aexpr)
|
| + continue;
|
| + }
|
| +
|
| + /* If we have a NULL bytecode expression, it means something
|
| + went wrong or we have a null command expression. */
|
| + if (!loc->cmd_bytecode)
|
| + {
|
| + null_command_or_parse_error = 1;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* If anything failed, then we're not doing target-side commands,
|
| + and so clean up. */
|
| + if (null_command_or_parse_error)
|
| + {
|
| + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
|
| + {
|
| + loc = (*loc2p);
|
| + if (is_breakpoint (loc->owner)
|
| + && loc->pspace->num == bl->pspace->num)
|
| + {
|
| + /* Only go as far as the first NULL bytecode is
|
| + located. */
|
| + if (!loc->cond_bytecode)
|
| + return;
|
| +
|
| + free_agent_expr (loc->cond_bytecode);
|
| + loc->cond_bytecode = NULL;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* No NULL commands or failed bytecode generation. Build a command list
|
| + for this location's address. */
|
| + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
|
| + {
|
| + loc = (*loc2p);
|
| + if (loc->owner->extra_string
|
| + && is_breakpoint (loc->owner)
|
| + && loc->pspace->num == bl->pspace->num
|
| + && loc->owner->enable_state == bp_enabled
|
| + && loc->enabled)
|
| + /* Add the command to the vector. This will be used later
|
| + to send the commands to the target. */
|
| + VEC_safe_push (agent_expr_p, bl->target_info.tcommands,
|
| + loc->cmd_bytecode);
|
| + }
|
| +
|
| + bl->target_info.persist = 0;
|
| + /* Maybe flag this location as persistent. */
|
| + if (bl->owner->type == bp_dprintf && disconnected_dprintf)
|
| + bl->target_info.persist = 1;
|
| +}
|
| +
|
| /* Insert a low-level "breakpoint" of some type. BL is the breakpoint
|
| location. Any error messages are printed to TMP_ERROR_STREAM; and
|
| DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
|
| @@ -1648,15 +2379,35 @@ insert_bp_location (struct bp_location *bl,
|
| {
|
| int val = 0;
|
|
|
| - if (!should_be_inserted (bl) || bl->inserted)
|
| + if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
|
| return 0;
|
|
|
| - /* Initialize the target-specific information. */
|
| - memset (&bl->target_info, 0, sizeof (bl->target_info));
|
| + /* Note we don't initialize bl->target_info, as that wipes out
|
| + the breakpoint location's shadow_contents if the breakpoint
|
| + is still inserted at that location. This in turn breaks
|
| + target_read_memory which depends on these buffers when
|
| + a memory read is requested at the breakpoint location:
|
| + Once the target_info has been wiped, we fail to see that
|
| + we have a breakpoint inserted at that address and thus
|
| + read the breakpoint instead of returning the data saved in
|
| + the breakpoint location's shadow contents. */
|
| bl->target_info.placed_address = bl->address;
|
| bl->target_info.placed_address_space = bl->pspace->aspace;
|
| bl->target_info.length = bl->length;
|
|
|
| + /* When working with target-side conditions, we must pass all the conditions
|
| + for the same breakpoint address down to the target since GDB will not
|
| + insert those locations. With a list of breakpoint conditions, the target
|
| + can decide when to stop and notify GDB. */
|
| +
|
| + if (is_breakpoint (bl->owner))
|
| + {
|
| + build_target_condition_list (bl);
|
| + build_target_command_list (bl);
|
| + /* Reset the modification marker. */
|
| + bl->needs_update = 0;
|
| + }
|
| +
|
| if (bl->loc_type == bp_loc_software_breakpoint
|
| || bl->loc_type == bp_loc_hardware_breakpoint)
|
| {
|
| @@ -1965,6 +2716,79 @@ insert_breakpoints (void)
|
| insert_breakpoint_locations ();
|
| }
|
|
|
| +/* Invoke CALLBACK for each of bp_location. */
|
| +
|
| +void
|
| +iterate_over_bp_locations (walk_bp_location_callback callback)
|
| +{
|
| + struct bp_location *loc, **loc_tmp;
|
| +
|
| + ALL_BP_LOCATIONS (loc, loc_tmp)
|
| + {
|
| + callback (loc, NULL);
|
| + }
|
| +}
|
| +
|
| +/* This is used when we need to synch breakpoint conditions between GDB and the
|
| + target. It is the case with deleting and disabling of breakpoints when using
|
| + always-inserted mode. */
|
| +
|
| +static void
|
| +update_inserted_breakpoint_locations (void)
|
| +{
|
| + struct bp_location *bl, **blp_tmp;
|
| + int error_flag = 0;
|
| + int val = 0;
|
| + int disabled_breaks = 0;
|
| + int hw_breakpoint_error = 0;
|
| +
|
| + struct ui_file *tmp_error_stream = mem_fileopen ();
|
| + struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
|
| +
|
| + /* Explicitly mark the warning -- this will only be printed if
|
| + there was an error. */
|
| + fprintf_unfiltered (tmp_error_stream, "Warning:\n");
|
| +
|
| + save_current_space_and_thread ();
|
| +
|
| + ALL_BP_LOCATIONS (bl, blp_tmp)
|
| + {
|
| + /* We only want to update software breakpoints and hardware
|
| + breakpoints. */
|
| + if (!is_breakpoint (bl->owner))
|
| + continue;
|
| +
|
| + /* We only want to update locations that are already inserted
|
| + and need updating. This is to avoid unwanted insertion during
|
| + deletion of breakpoints. */
|
| + if (!bl->inserted || (bl->inserted && !bl->needs_update))
|
| + continue;
|
| +
|
| + switch_to_program_space_and_thread (bl->pspace);
|
| +
|
| + /* For targets that support global breakpoints, there's no need
|
| + to select an inferior to insert breakpoint to. In fact, even
|
| + if we aren't attached to any process yet, we should still
|
| + insert breakpoints. */
|
| + if (!gdbarch_has_global_breakpoints (target_gdbarch)
|
| + && ptid_equal (inferior_ptid, null_ptid))
|
| + continue;
|
| +
|
| + val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks,
|
| + &hw_breakpoint_error);
|
| + if (val)
|
| + error_flag = val;
|
| + }
|
| +
|
| + if (error_flag)
|
| + {
|
| + target_terminal_ours_for_output ();
|
| + error_stream (tmp_error_stream);
|
| + }
|
| +
|
| + do_cleanups (cleanups);
|
| +}
|
| +
|
| /* Used when starting or continuing the program. */
|
|
|
| static void
|
| @@ -1988,7 +2812,7 @@ insert_breakpoint_locations (void)
|
|
|
| ALL_BP_LOCATIONS (bl, blp_tmp)
|
| {
|
| - if (!should_be_inserted (bl) || bl->inserted)
|
| + if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
|
| continue;
|
|
|
| /* There is no point inserting thread-specific breakpoints if
|
| @@ -2099,6 +2923,9 @@ remove_breakpoints_pid (int pid)
|
| if (bl->pspace != inf->pspace)
|
| continue;
|
|
|
| + if (bl->owner->type == bp_dprintf)
|
| + continue;
|
| +
|
| if (bl->inserted)
|
| {
|
| val = remove_breakpoint (bl, mark_uninserted);
|
| @@ -2208,11 +3035,23 @@ struct breakpoint_objfile_data
|
| /* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
|
| struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
|
|
|
| + /* True if we have looked for longjmp probes. */
|
| + int longjmp_searched;
|
| +
|
| + /* SystemTap probe points for longjmp (if any). */
|
| + VEC (probe_p) *longjmp_probes;
|
| +
|
| /* Minimal symbol for "std::terminate()" (if any). */
|
| struct minimal_symbol *terminate_msym;
|
|
|
| /* Minimal symbol for "_Unwind_DebugHook" (if any). */
|
| struct minimal_symbol *exception_msym;
|
| +
|
| + /* True if we have looked for exception probes. */
|
| + int exception_searched;
|
| +
|
| + /* SystemTap probe points for unwinding (if any). */
|
| + VEC (probe_p) *exception_probes;
|
| };
|
|
|
| static const struct objfile_data *breakpoint_objfile_key;
|
| @@ -2249,6 +3088,15 @@ get_breakpoint_objfile_data (struct objfile *objfile)
|
| }
|
|
|
| static void
|
| +free_breakpoint_probes (struct objfile *obj, void *data)
|
| +{
|
| + struct breakpoint_objfile_data *bp_objfile_data = data;
|
| +
|
| + VEC_free (probe_p, bp_objfile_data->longjmp_probes);
|
| + VEC_free (probe_p, bp_objfile_data->exception_probes);
|
| +}
|
| +
|
| +static void
|
| create_overlay_event_breakpoint (void)
|
| {
|
| struct objfile *objfile;
|
| @@ -2325,6 +3173,37 @@ create_longjmp_master_breakpoint (void)
|
|
|
| bp_objfile_data = get_breakpoint_objfile_data (objfile);
|
|
|
| + if (!bp_objfile_data->longjmp_searched)
|
| + {
|
| + bp_objfile_data->longjmp_probes
|
| + = find_probes_in_objfile (objfile, "libc", "longjmp");
|
| + bp_objfile_data->longjmp_searched = 1;
|
| + }
|
| +
|
| + if (bp_objfile_data->longjmp_probes != NULL)
|
| + {
|
| + int i;
|
| + struct probe *probe;
|
| + struct gdbarch *gdbarch = get_objfile_arch (objfile);
|
| +
|
| + for (i = 0;
|
| + VEC_iterate (probe_p,
|
| + bp_objfile_data->longjmp_probes,
|
| + i, probe);
|
| + ++i)
|
| + {
|
| + struct breakpoint *b;
|
| +
|
| + b = create_internal_breakpoint (gdbarch, probe->address,
|
| + bp_longjmp_master,
|
| + &internal_breakpoint_ops);
|
| + b->addr_string = xstrdup ("-probe-stap libc:longjmp");
|
| + b->enable_state = bp_disabled;
|
| + }
|
| +
|
| + continue;
|
| + }
|
| +
|
| for (i = 0; i < NUM_LONGJMP_NAMES; i++)
|
| {
|
| struct breakpoint *b;
|
| @@ -2420,7 +3299,7 @@ create_std_terminate_master_breakpoint (void)
|
|
|
| /* Install a master breakpoint on the unwinder's debug hook. */
|
|
|
| -void
|
| +static void
|
| create_exception_master_breakpoint (void)
|
| {
|
| struct objfile *objfile;
|
| @@ -2435,6 +3314,40 @@ create_exception_master_breakpoint (void)
|
|
|
| bp_objfile_data = get_breakpoint_objfile_data (objfile);
|
|
|
| + /* We prefer the SystemTap probe point if it exists. */
|
| + if (!bp_objfile_data->exception_searched)
|
| + {
|
| + bp_objfile_data->exception_probes
|
| + = find_probes_in_objfile (objfile, "libgcc", "unwind");
|
| + bp_objfile_data->exception_searched = 1;
|
| + }
|
| +
|
| + if (bp_objfile_data->exception_probes != NULL)
|
| + {
|
| + struct gdbarch *gdbarch = get_objfile_arch (objfile);
|
| + int i;
|
| + struct probe *probe;
|
| +
|
| + for (i = 0;
|
| + VEC_iterate (probe_p,
|
| + bp_objfile_data->exception_probes,
|
| + i, probe);
|
| + ++i)
|
| + {
|
| + struct breakpoint *b;
|
| +
|
| + b = create_internal_breakpoint (gdbarch, probe->address,
|
| + bp_exception_master,
|
| + &internal_breakpoint_ops);
|
| + b->addr_string = xstrdup ("-probe-stap libgcc:unwind");
|
| + b->enable_state = bp_disabled;
|
| + }
|
| +
|
| + continue;
|
| + }
|
| +
|
| + /* Otherwise, try the hook function. */
|
| +
|
| if (msym_not_found_p (bp_objfile_data->exception_msym))
|
| continue;
|
|
|
| @@ -2523,6 +3436,7 @@ update_breakpoints_after_exec (void)
|
| /* Longjmp and longjmp-resume breakpoints are also meaningless
|
| after an exec. */
|
| if (b->type == bp_longjmp || b->type == bp_longjmp_resume
|
| + || b->type == bp_longjmp_call_dummy
|
| || b->type == bp_exception || b->type == bp_exception_resume)
|
| {
|
| delete_breakpoint (b);
|
| @@ -2814,6 +3728,7 @@ breakpoint_init_inferior (enum inf_context context)
|
| switch (b->type)
|
| {
|
| case bp_call_dummy:
|
| + case bp_longjmp_call_dummy:
|
|
|
| /* If the call dummy breakpoint is at the entry point it will
|
| cause problems when the inferior is rerun, so we better get
|
| @@ -2839,6 +3754,10 @@ breakpoint_init_inferior (enum inf_context context)
|
| (gdb) tar rem :9999 # remote Windows gdbserver.
|
| */
|
|
|
| + case bp_step_resume:
|
| +
|
| + /* Also remove step-resume breakpoints. */
|
| +
|
| delete_breakpoint (b);
|
| break;
|
|
|
| @@ -3111,7 +4030,7 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
|
| in breakpoint.h. */
|
|
|
| int
|
| -ep_is_catchpoint (struct breakpoint *ep)
|
| +is_catchpoint (struct breakpoint *ep)
|
| {
|
| return (ep->type == bp_catchpoint);
|
| }
|
| @@ -3473,6 +4392,78 @@ print_bp_stop_message (bpstat bs)
|
| }
|
| }
|
|
|
| +/* A helper function that prints a shared library stopped event. */
|
| +
|
| +static void
|
| +print_solib_event (int is_catchpoint)
|
| +{
|
| + int any_deleted
|
| + = !VEC_empty (char_ptr, current_program_space->deleted_solibs);
|
| + int any_added
|
| + = !VEC_empty (so_list_ptr, current_program_space->added_solibs);
|
| +
|
| + if (!is_catchpoint)
|
| + {
|
| + if (any_added || any_deleted)
|
| + ui_out_text (current_uiout,
|
| + _("Stopped due to shared library event:\n"));
|
| + else
|
| + ui_out_text (current_uiout,
|
| + _("Stopped due to shared library event (no "
|
| + "libraries added or removed)\n"));
|
| + }
|
| +
|
| + if (ui_out_is_mi_like_p (current_uiout))
|
| + ui_out_field_string (current_uiout, "reason",
|
| + async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT));
|
| +
|
| + if (any_deleted)
|
| + {
|
| + struct cleanup *cleanup;
|
| + char *name;
|
| + int ix;
|
| +
|
| + ui_out_text (current_uiout, _(" Inferior unloaded "));
|
| + cleanup = make_cleanup_ui_out_list_begin_end (current_uiout,
|
| + "removed");
|
| + for (ix = 0;
|
| + VEC_iterate (char_ptr, current_program_space->deleted_solibs,
|
| + ix, name);
|
| + ++ix)
|
| + {
|
| + if (ix > 0)
|
| + ui_out_text (current_uiout, " ");
|
| + ui_out_field_string (current_uiout, "library", name);
|
| + ui_out_text (current_uiout, "\n");
|
| + }
|
| +
|
| + do_cleanups (cleanup);
|
| + }
|
| +
|
| + if (any_added)
|
| + {
|
| + struct so_list *iter;
|
| + int ix;
|
| + struct cleanup *cleanup;
|
| +
|
| + ui_out_text (current_uiout, _(" Inferior loaded "));
|
| + cleanup = make_cleanup_ui_out_list_begin_end (current_uiout,
|
| + "added");
|
| + for (ix = 0;
|
| + VEC_iterate (so_list_ptr, current_program_space->added_solibs,
|
| + ix, iter);
|
| + ++ix)
|
| + {
|
| + if (ix > 0)
|
| + ui_out_text (current_uiout, " ");
|
| + ui_out_field_string (current_uiout, "library", iter->so_name);
|
| + ui_out_text (current_uiout, "\n");
|
| + }
|
| +
|
| + do_cleanups (cleanup);
|
| + }
|
| +}
|
| +
|
| /* Print a message indicating what happened. This is called from
|
| normal_stop(). The input to this routine is the head of the bpstat
|
| list - a list of the eventpoints that caused this stop. KIND is
|
| @@ -3517,10 +4508,7 @@ bpstat_print (bpstat bs, int kind)
|
| OS-level shared library event, do the same thing. */
|
| if (kind == TARGET_WAITKIND_LOADED)
|
| {
|
| - ui_out_text (current_uiout, _("Stopped due to shared library event\n"));
|
| - if (ui_out_is_mi_like_p (current_uiout))
|
| - ui_out_field_string (current_uiout, "reason",
|
| - async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT));
|
| + print_solib_event (0);
|
| return PRINT_NOTHING;
|
| }
|
|
|
| @@ -3808,14 +4796,15 @@ which its expression is valid.\n");
|
|
|
| static int
|
| bpstat_check_location (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct breakpoint *b = bl->owner;
|
|
|
| /* BL is from an existing breakpoint. */
|
| gdb_assert (b != NULL);
|
|
|
| - return b->ops->breakpoint_hit (bl, aspace, bp_addr);
|
| + return b->ops->breakpoint_hit (bl, aspace, bp_addr, ws);
|
| }
|
|
|
| /* Determine if the watched values have actually changed, and we
|
| @@ -3996,6 +4985,10 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
|
| b = bs->breakpoint_at;
|
| gdb_assert (b != NULL);
|
|
|
| + /* Even if the target evaluated the condition on its end and notified GDB, we
|
| + need to do so again since GDB does not know if we stopped due to a
|
| + breakpoint or a single step breakpoint. */
|
| +
|
| if (frame_id_p (b->frame_id)
|
| && !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ())))
|
| bs->stop = 0;
|
| @@ -4125,7 +5118,8 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
|
|
|
| bpstat
|
| bpstat_stop_status (struct address_space *aspace,
|
| - CORE_ADDR bp_addr, ptid_t ptid)
|
| + CORE_ADDR bp_addr, ptid_t ptid,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct breakpoint *b = NULL;
|
| struct bp_location *bl;
|
| @@ -4163,7 +5157,7 @@ bpstat_stop_status (struct address_space *aspace,
|
| if (bl->shlib_disabled)
|
| continue;
|
|
|
| - if (!bpstat_check_location (bl, aspace, bp_addr))
|
| + if (!bpstat_check_location (bl, aspace, bp_addr, ws))
|
| continue;
|
|
|
| /* Come here if it's a watchpoint, or if the break address
|
| @@ -4203,6 +5197,19 @@ bpstat_stop_status (struct address_space *aspace,
|
| }
|
| }
|
|
|
| + /* A bit of special processing for shlib breakpoints. We need to
|
| + process solib loading here, so that the lists of loaded and
|
| + unloaded libraries are correct before we handle "catch load" and
|
| + "catch unload". */
|
| + for (bs = bs_head; bs != NULL; bs = bs->next)
|
| + {
|
| + if (bs->breakpoint_at && bs->breakpoint_at->type == bp_shlib_event)
|
| + {
|
| + handle_solib_event ();
|
| + break;
|
| + }
|
| + }
|
| +
|
| /* Now go through the locations that caused the target to stop, and
|
| check whether we're interested in reporting this stop to higher
|
| layers, or whether we should resume the target transparently. */
|
| @@ -4228,7 +5235,9 @@ bpstat_stop_status (struct address_space *aspace,
|
| /* We will stop here. */
|
| if (b->disposition == disp_disable)
|
| {
|
| - if (b->enable_state != bp_permanent)
|
| + --(b->enable_count);
|
| + if (b->enable_count <= 0
|
| + && b->enable_state != bp_permanent)
|
| b->enable_state = bp_disabled;
|
| removed_any = 1;
|
| }
|
| @@ -4241,10 +5250,12 @@ bpstat_stop_status (struct address_space *aspace,
|
| bs->print = 0;
|
| }
|
|
|
| - /* Print nothing for this entry if we don't stop or don't print. */
|
| - if (bs->stop == 0 || bs->print == 0)
|
| - bs->print_it = print_it_noop;
|
| }
|
| +
|
| + /* Print nothing for this entry if we don't stop or don't
|
| + print. */
|
| + if (!bs->stop || !bs->print)
|
| + bs->print_it = print_it_noop;
|
| }
|
|
|
| /* If we aren't stopping, the value of some hardware watchpoint may
|
| @@ -4290,6 +5301,25 @@ handle_jit_event (void)
|
| target_terminal_inferior ();
|
| }
|
|
|
| +/* Handle an solib event by calling solib_add. */
|
| +
|
| +void
|
| +handle_solib_event (void)
|
| +{
|
| + clear_program_space_solib_cache (current_inferior ()->pspace);
|
| +
|
| + /* Check for any newly added shared libraries if we're supposed to
|
| + be adding them automatically. Switch terminal for any messages
|
| + produced by breakpoint_re_set. */
|
| + target_terminal_ours_for_output ();
|
| +#ifdef SOLIB_ADD
|
| + SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
|
| +#else
|
| + solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
| +#endif
|
| + target_terminal_inferior ();
|
| +}
|
| +
|
| /* Prepare WHAT final decision for infrun. */
|
|
|
| /* Decide what infrun needs to do with this bpstat. */
|
| @@ -4298,10 +5328,6 @@ struct bpstat_what
|
| bpstat_what (bpstat bs_head)
|
| {
|
| struct bpstat_what retval;
|
| - /* We need to defer calling `solib_add', as adding new symbols
|
| - resets breakpoints, which in turn deletes breakpoint locations,
|
| - and hence may clear unprocessed entries in the BS chain. */
|
| - int shlib_event = 0;
|
| int jit_event = 0;
|
| bpstat bs;
|
|
|
| @@ -4333,6 +5359,7 @@ bpstat_what (bpstat bs_head)
|
| case bp_hardware_breakpoint:
|
| case bp_until:
|
| case bp_finish:
|
| + case bp_shlib_event:
|
| if (bs->stop)
|
| {
|
| if (bs->print)
|
| @@ -4361,9 +5388,10 @@ bpstat_what (bpstat bs_head)
|
| }
|
| break;
|
| case bp_longjmp:
|
| + case bp_longjmp_call_dummy:
|
| case bp_exception:
|
| this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME;
|
| - retval.is_longjmp = bptype == bp_longjmp;
|
| + retval.is_longjmp = bptype != bp_exception;
|
| break;
|
| case bp_longjmp_resume:
|
| case bp_exception_resume:
|
| @@ -4410,18 +5438,6 @@ bpstat_what (bpstat bs_head)
|
| This requires no further action. */
|
| }
|
| break;
|
| - case bp_shlib_event:
|
| - shlib_event = 1;
|
| -
|
| - /* If requested, stop when the dynamic linker notifies GDB
|
| - of events. This allows the user to get control and place
|
| - breakpoints in initializer routines for dynamically
|
| - loaded objects (among other things). */
|
| - if (stop_on_solib_events)
|
| - this_action = BPSTAT_WHAT_STOP_NOISY;
|
| - else
|
| - this_action = BPSTAT_WHAT_SINGLE;
|
| - break;
|
| case bp_jit_event:
|
| jit_event = 1;
|
| this_action = BPSTAT_WHAT_SINGLE;
|
| @@ -4456,6 +5472,11 @@ bpstat_what (bpstat bs_head)
|
| PC of the former breakpoint. */
|
| this_action = BPSTAT_WHAT_KEEP_CHECKING;
|
| break;
|
| +
|
| + case bp_dprintf:
|
| + this_action = BPSTAT_WHAT_STOP_SILENT;
|
| + break;
|
| +
|
| default:
|
| internal_error (__FILE__, __LINE__,
|
| _("bpstat_what: unhandled bptype %d"), (int) bptype);
|
| @@ -4467,27 +5488,6 @@ bpstat_what (bpstat bs_head)
|
| /* These operations may affect the bs->breakpoint_at state so they are
|
| delayed after MAIN_ACTION is decided above. */
|
|
|
| - if (shlib_event)
|
| - {
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "bpstat_what: bp_shlib_event\n");
|
| -
|
| - /* Check for any newly added shared libraries if we're supposed
|
| - to be adding them automatically. */
|
| -
|
| - /* Switch terminal for any messages produced by
|
| - breakpoint_re_set. */
|
| - target_terminal_ours_for_output ();
|
| -
|
| -#ifdef SOLIB_ADD
|
| - SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
|
| -#else
|
| - solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
| -#endif
|
| -
|
| - target_terminal_inferior ();
|
| - }
|
| -
|
| if (jit_event)
|
| {
|
| if (debug_infrun)
|
| @@ -4563,13 +5563,73 @@ wrap_indent_at_field (struct ui_out *uiout, const char *col_name)
|
| memset (wrap_indent, ' ', total_width);
|
| wrap_indent[total_width] = 0;
|
|
|
| - return wrap_indent;
|
| - }
|
| + return wrap_indent;
|
| + }
|
| +
|
| + total_width += width + 1;
|
| + }
|
| +
|
| + return NULL;
|
| +}
|
| +
|
| +/* Determine if the locations of this breakpoint will have their conditions
|
| + evaluated by the target, host or a mix of both. Returns the following:
|
| +
|
| + "host": Host evals condition.
|
| + "host or target": Host or Target evals condition.
|
| + "target": Target evals condition.
|
| +*/
|
| +
|
| +static const char *
|
| +bp_condition_evaluator (struct breakpoint *b)
|
| +{
|
| + struct bp_location *bl;
|
| + char host_evals = 0;
|
| + char target_evals = 0;
|
| +
|
| + if (!b)
|
| + return NULL;
|
| +
|
| + if (!is_breakpoint (b))
|
| + return NULL;
|
|
|
| - total_width += width + 1;
|
| + if (gdb_evaluates_breakpoint_condition_p ()
|
| + || !target_supports_evaluation_of_breakpoint_conditions ())
|
| + return condition_evaluation_host;
|
| +
|
| + for (bl = b->loc; bl; bl = bl->next)
|
| + {
|
| + if (bl->cond_bytecode)
|
| + target_evals++;
|
| + else
|
| + host_evals++;
|
| }
|
|
|
| - return NULL;
|
| + if (host_evals && target_evals)
|
| + return condition_evaluation_both;
|
| + else if (target_evals)
|
| + return condition_evaluation_target;
|
| + else
|
| + return condition_evaluation_host;
|
| +}
|
| +
|
| +/* Determine the breakpoint location's condition evaluator. This is
|
| + similar to bp_condition_evaluator, but for locations. */
|
| +
|
| +static const char *
|
| +bp_location_condition_evaluator (struct bp_location *bl)
|
| +{
|
| + if (bl && !is_breakpoint (bl->owner))
|
| + return NULL;
|
| +
|
| + if (gdb_evaluates_breakpoint_condition_p ()
|
| + || !target_supports_evaluation_of_breakpoint_conditions ())
|
| + return condition_evaluation_host;
|
| +
|
| + if (bl && bl->cond_bytecode)
|
| + return condition_evaluation_target;
|
| + else
|
| + return condition_evaluation_host;
|
| }
|
|
|
| /* Print the LOC location out of the list of B->LOC locations. */
|
| @@ -4618,10 +5678,10 @@ print_breakpoint_location (struct breakpoint *b,
|
| }
|
| else if (loc)
|
| {
|
| - struct ui_stream *stb = ui_out_stream_new (uiout);
|
| - struct cleanup *stb_chain = make_cleanup_ui_out_stream_delete (stb);
|
| + struct ui_file *stb = mem_fileopen ();
|
| + struct cleanup *stb_chain = make_cleanup_ui_file_delete (stb);
|
|
|
| - print_address_symbolic (loc->gdbarch, loc->address, stb->stream,
|
| + print_address_symbolic (loc->gdbarch, loc->address, stb,
|
| demangle, "");
|
| ui_out_field_stream (uiout, "at", stb);
|
|
|
| @@ -4630,6 +5690,16 @@ print_breakpoint_location (struct breakpoint *b,
|
| else
|
| ui_out_field_string (uiout, "pending", b->addr_string);
|
|
|
| + if (loc && is_breakpoint (b)
|
| + && breakpoint_condition_evaluation_mode () == condition_evaluation_target
|
| + && bp_condition_evaluator (b) == condition_evaluation_both)
|
| + {
|
| + ui_out_text (uiout, " (");
|
| + ui_out_field_string (uiout, "evaluated-by",
|
| + bp_location_condition_evaluator (loc));
|
| + ui_out_text (uiout, ")");
|
| + }
|
| +
|
| do_cleanups (old_chain);
|
| }
|
|
|
| @@ -4654,6 +5724,7 @@ bptype_string (enum bptype type)
|
| {bp_access_watchpoint, "acc watchpoint"},
|
| {bp_longjmp, "longjmp"},
|
| {bp_longjmp_resume, "longjmp resume"},
|
| + {bp_longjmp_call_dummy, "longjmp for call dummy"},
|
| {bp_exception, "exception"},
|
| {bp_exception_resume, "exception resume"},
|
| {bp_step_resume, "step resume"},
|
| @@ -4671,6 +5742,7 @@ bptype_string (enum bptype type)
|
| {bp_tracepoint, "tracepoint"},
|
| {bp_fast_tracepoint, "fast tracepoint"},
|
| {bp_static_tracepoint, "static tracepoint"},
|
| + {bp_dprintf, "dprintf"},
|
| {bp_jit_event, "jit events"},
|
| {bp_gnu_ifunc_resolver, "STT_GNU_IFUNC resolver"},
|
| {bp_gnu_ifunc_resolver_return, "STT_GNU_IFUNC resolver return"},
|
| @@ -4795,6 +5867,7 @@ print_one_breakpoint_location (struct breakpoint *b,
|
| case bp_finish:
|
| case bp_longjmp:
|
| case bp_longjmp_resume:
|
| + case bp_longjmp_call_dummy:
|
| case bp_exception:
|
| case bp_exception_resume:
|
| case bp_step_resume:
|
| @@ -4811,6 +5884,7 @@ print_one_breakpoint_location (struct breakpoint *b,
|
| case bp_tracepoint:
|
| case bp_fast_tracepoint:
|
| case bp_static_tracepoint:
|
| + case bp_dprintf:
|
| case bp_jit_event:
|
| case bp_gnu_ifunc_resolver:
|
| case bp_gnu_ifunc_resolver_return:
|
| @@ -4905,6 +5979,18 @@ print_one_breakpoint_location (struct breakpoint *b,
|
| else
|
| ui_out_text (uiout, "\tstop only if ");
|
| ui_out_field_string (uiout, "cond", b->cond_string);
|
| +
|
| + /* Print whether the target is doing the breakpoint's condition
|
| + evaluation. If GDB is doing the evaluation, don't print anything. */
|
| + if (is_breakpoint (b)
|
| + && breakpoint_condition_evaluation_mode ()
|
| + == condition_evaluation_target)
|
| + {
|
| + ui_out_text (uiout, " (");
|
| + ui_out_field_string (uiout, "evaluated-by",
|
| + bp_condition_evaluator (b));
|
| + ui_out_text (uiout, " evals)");
|
| + }
|
| ui_out_text (uiout, "\n");
|
| }
|
|
|
| @@ -4919,7 +6005,7 @@ print_one_breakpoint_location (struct breakpoint *b,
|
| if (!part_of_multiple && b->hit_count)
|
| {
|
| /* FIXME should make an annotation for this. */
|
| - if (ep_is_catchpoint (b))
|
| + if (is_catchpoint (b))
|
| ui_out_text (uiout, "\tcatchpoint");
|
| else if (is_tracepoint (b))
|
| ui_out_text (uiout, "\ttracepoint");
|
| @@ -4947,6 +6033,23 @@ print_one_breakpoint_location (struct breakpoint *b,
|
| ui_out_text (uiout, " hits\n");
|
| }
|
|
|
| + /* Note that an enable count of 1 corresponds to "enable once"
|
| + behavior, which is reported by the combination of enablement and
|
| + disposition, so we don't need to mention it here. */
|
| + if (!part_of_multiple && b->enable_count > 1)
|
| + {
|
| + annotate_field (8);
|
| + ui_out_text (uiout, "\tdisable after ");
|
| + /* Tweak the wording to clarify that ignore and enable counts
|
| + are distinct, and have additive effect. */
|
| + if (b->ignore_count)
|
| + ui_out_text (uiout, "additional ");
|
| + else
|
| + ui_out_text (uiout, "next ");
|
| + ui_out_field_int (uiout, "enable", b->enable_count);
|
| + ui_out_text (uiout, " hits\n");
|
| + }
|
| +
|
| if (!part_of_multiple && is_tracepoint (b))
|
| {
|
| struct tracepoint *tp = (struct tracepoint *) b;
|
| @@ -4959,6 +6062,15 @@ print_one_breakpoint_location (struct breakpoint *b,
|
| }
|
| }
|
|
|
| + if (!part_of_multiple && b->extra_string
|
| + && b->type == bp_dprintf && !b->commands)
|
| + {
|
| + annotate_field (7);
|
| + ui_out_text (uiout, "\t(agent printf) ");
|
| + ui_out_field_string (uiout, "printf", b->extra_string);
|
| + ui_out_text (uiout, "\n");
|
| + }
|
| +
|
| l = b->commands ? b->commands->commands : NULL;
|
| if (!part_of_multiple && l)
|
| {
|
| @@ -5617,6 +6729,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
|
| loc->ops = ops;
|
| loc->owner = owner;
|
| loc->cond = NULL;
|
| + loc->cond_bytecode = NULL;
|
| loc->shlib_disabled = 0;
|
| loc->enabled = 1;
|
|
|
| @@ -5627,6 +6740,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
|
| case bp_finish:
|
| case bp_longjmp:
|
| case bp_longjmp_resume:
|
| + case bp_longjmp_call_dummy:
|
| case bp_exception:
|
| case bp_exception_resume:
|
| case bp_step_resume:
|
| @@ -5643,10 +6757,13 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
|
| case bp_exception_master:
|
| case bp_gnu_ifunc_resolver:
|
| case bp_gnu_ifunc_resolver_return:
|
| + case bp_dprintf:
|
| loc->loc_type = bp_loc_software_breakpoint;
|
| + mark_breakpoint_location_modified (loc);
|
| break;
|
| case bp_hardware_breakpoint:
|
| loc->loc_type = bp_loc_hardware_breakpoint;
|
| + mark_breakpoint_location_modified (loc);
|
| break;
|
| case bp_hardware_watchpoint:
|
| case bp_read_watchpoint:
|
| @@ -5782,16 +6899,18 @@ set_breakpoint_location_function (struct bp_location *loc, int explicit_loc)
|
| || is_tracepoint (loc->owner))
|
| {
|
| int is_gnu_ifunc;
|
| + const char *function_name;
|
| + CORE_ADDR func_addr;
|
|
|
| - find_pc_partial_function_gnu_ifunc (loc->address, &loc->function_name,
|
| - NULL, NULL, &is_gnu_ifunc);
|
| + find_pc_partial_function_gnu_ifunc (loc->address, &function_name,
|
| + &func_addr, NULL, &is_gnu_ifunc);
|
|
|
| if (is_gnu_ifunc && !explicit_loc)
|
| {
|
| struct breakpoint *b = loc->owner;
|
|
|
| gdb_assert (loc->pspace == current_program_space);
|
| - if (gnu_ifunc_resolve_name (loc->function_name,
|
| + if (gnu_ifunc_resolve_name (function_name,
|
| &loc->requested_address))
|
| {
|
| /* Recalculate ADDRESS based on new REQUESTED_ADDRESS. */
|
| @@ -5805,11 +6924,14 @@ set_breakpoint_location_function (struct bp_location *loc, int explicit_loc)
|
| /* Create only the whole new breakpoint of this type but do not
|
| mess more complicated breakpoints with multiple locations. */
|
| b->type = bp_gnu_ifunc_resolver;
|
| + /* Remember the resolver's address for use by the return
|
| + breakpoint. */
|
| + loc->related_address = func_addr;
|
| }
|
| }
|
|
|
| - if (loc->function_name)
|
| - loc->function_name = xstrdup (loc->function_name);
|
| + if (function_name)
|
| + loc->function_name = xstrdup (function_name);
|
| }
|
| }
|
|
|
| @@ -5922,8 +7044,10 @@ set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
|
| enum bptype type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
|
| struct breakpoint *clone;
|
|
|
| + /* longjmp_breakpoint_ops ensures INITIATING_FRAME is cleared again
|
| + after their removal. */
|
| clone = momentary_breakpoint_from_master (b, type,
|
| - &momentary_breakpoint_ops);
|
| + &longjmp_breakpoint_ops);
|
| clone->thread = thread;
|
| }
|
|
|
| @@ -5945,6 +7069,88 @@ delete_longjmp_breakpoint (int thread)
|
| }
|
|
|
| void
|
| +delete_longjmp_breakpoint_at_next_stop (int thread)
|
| +{
|
| + struct breakpoint *b, *b_tmp;
|
| +
|
| + ALL_BREAKPOINTS_SAFE (b, b_tmp)
|
| + if (b->type == bp_longjmp || b->type == bp_exception)
|
| + {
|
| + if (b->thread == thread)
|
| + b->disposition = disp_del_at_next_stop;
|
| + }
|
| +}
|
| +
|
| +/* Place breakpoints of type bp_longjmp_call_dummy to catch longjmp for
|
| + INFERIOR_PTID thread. Chain them all by RELATED_BREAKPOINT and return
|
| + pointer to any of them. Return NULL if this system cannot place longjmp
|
| + breakpoints. */
|
| +
|
| +struct breakpoint *
|
| +set_longjmp_breakpoint_for_call_dummy (void)
|
| +{
|
| + struct breakpoint *b, *retval = NULL;
|
| +
|
| + ALL_BREAKPOINTS (b)
|
| + if (b->pspace == current_program_space && b->type == bp_longjmp_master)
|
| + {
|
| + struct breakpoint *new_b;
|
| +
|
| + new_b = momentary_breakpoint_from_master (b, bp_longjmp_call_dummy,
|
| + &momentary_breakpoint_ops);
|
| + new_b->thread = pid_to_thread_id (inferior_ptid);
|
| +
|
| + /* Link NEW_B into the chain of RETVAL breakpoints. */
|
| +
|
| + gdb_assert (new_b->related_breakpoint == new_b);
|
| + if (retval == NULL)
|
| + retval = new_b;
|
| + new_b->related_breakpoint = retval;
|
| + while (retval->related_breakpoint != new_b->related_breakpoint)
|
| + retval = retval->related_breakpoint;
|
| + retval->related_breakpoint = new_b;
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +/* Verify all existing dummy frames and their associated breakpoints for
|
| + THREAD. Remove those which can no longer be found in the current frame
|
| + stack.
|
| +
|
| + You should call this function only at places where it is safe to currently
|
| + unwind the whole stack. Failed stack unwind would discard live dummy
|
| + frames. */
|
| +
|
| +void
|
| +check_longjmp_breakpoint_for_call_dummy (int thread)
|
| +{
|
| + struct breakpoint *b, *b_tmp;
|
| +
|
| + ALL_BREAKPOINTS_SAFE (b, b_tmp)
|
| + if (b->type == bp_longjmp_call_dummy && b->thread == thread)
|
| + {
|
| + struct breakpoint *dummy_b = b->related_breakpoint;
|
| +
|
| + while (dummy_b != b && dummy_b->type != bp_call_dummy)
|
| + dummy_b = dummy_b->related_breakpoint;
|
| + if (dummy_b->type != bp_call_dummy
|
| + || frame_find_by_id (dummy_b->frame_id) != NULL)
|
| + continue;
|
| +
|
| + dummy_frame_discard (dummy_b->frame_id);
|
| +
|
| + while (b->related_breakpoint != b)
|
| + {
|
| + if (b_tmp == b->related_breakpoint)
|
| + b_tmp = b->related_breakpoint->next;
|
| + delete_breakpoint (b->related_breakpoint);
|
| + }
|
| + delete_breakpoint (b);
|
| + }
|
| +}
|
| +
|
| +void
|
| enable_overlay_breakpoints (void)
|
| {
|
| struct breakpoint *b;
|
| @@ -6214,11 +7420,16 @@ remove_catch_fork (struct bp_location *bl)
|
|
|
| static int
|
| breakpoint_hit_catch_fork (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
|
|
|
| - return inferior_has_forked (inferior_ptid, &c->forked_inferior_pid);
|
| + if (ws->kind != TARGET_WAITKIND_FORKED)
|
| + return 0;
|
| +
|
| + c->forked_inferior_pid = ws->value.related_pid;
|
| + return 1;
|
| }
|
|
|
| /* Implement the "print_it" breakpoint_ops method for fork
|
| @@ -6323,11 +7534,16 @@ remove_catch_vfork (struct bp_location *bl)
|
|
|
| static int
|
| breakpoint_hit_catch_vfork (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
|
|
|
| - return inferior_has_vforked (inferior_ptid, &c->forked_inferior_pid);
|
| + if (ws->kind != TARGET_WAITKIND_VFORKED)
|
| + return 0;
|
| +
|
| + c->forked_inferior_pid = ws->value.related_pid;
|
| + return 1;
|
| }
|
|
|
| /* Implement the "print_it" breakpoint_ops method for vfork
|
| @@ -6378,35 +7594,294 @@ print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
|
| ui_out_text (uiout, "vfork");
|
| if (!ptid_equal (c->forked_inferior_pid, null_ptid))
|
| {
|
| - ui_out_text (uiout, ", process ");
|
| - ui_out_field_int (uiout, "what",
|
| - ptid_get_pid (c->forked_inferior_pid));
|
| - ui_out_spaces (uiout, 1);
|
| + ui_out_text (uiout, ", process ");
|
| + ui_out_field_int (uiout, "what",
|
| + ptid_get_pid (c->forked_inferior_pid));
|
| + ui_out_spaces (uiout, 1);
|
| + }
|
| +}
|
| +
|
| +/* Implement the "print_mention" breakpoint_ops method for vfork
|
| + catchpoints. */
|
| +
|
| +static void
|
| +print_mention_catch_vfork (struct breakpoint *b)
|
| +{
|
| + printf_filtered (_("Catchpoint %d (vfork)"), b->number);
|
| +}
|
| +
|
| +/* Implement the "print_recreate" breakpoint_ops method for vfork
|
| + catchpoints. */
|
| +
|
| +static void
|
| +print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp)
|
| +{
|
| + fprintf_unfiltered (fp, "catch vfork");
|
| + print_recreate_thread (b, fp);
|
| +}
|
| +
|
| +/* The breakpoint_ops structure to be used in vfork catchpoints. */
|
| +
|
| +static struct breakpoint_ops catch_vfork_breakpoint_ops;
|
| +
|
| +/* An instance of this type is used to represent an solib catchpoint.
|
| + It includes a "struct breakpoint" as a kind of base class; users
|
| + downcast to "struct breakpoint *" when needed. A breakpoint is
|
| + really of this type iff its ops pointer points to
|
| + CATCH_SOLIB_BREAKPOINT_OPS. */
|
| +
|
| +struct solib_catchpoint
|
| +{
|
| + /* The base class. */
|
| + struct breakpoint base;
|
| +
|
| + /* True for "catch load", false for "catch unload". */
|
| + unsigned char is_load;
|
| +
|
| + /* Regular expression to match, if any. COMPILED is only valid when
|
| + REGEX is non-NULL. */
|
| + char *regex;
|
| + regex_t compiled;
|
| +};
|
| +
|
| +static void
|
| +dtor_catch_solib (struct breakpoint *b)
|
| +{
|
| + struct solib_catchpoint *self = (struct solib_catchpoint *) b;
|
| +
|
| + if (self->regex)
|
| + regfree (&self->compiled);
|
| + xfree (self->regex);
|
| +
|
| + base_breakpoint_ops.dtor (b);
|
| +}
|
| +
|
| +static int
|
| +insert_catch_solib (struct bp_location *ignore)
|
| +{
|
| + return 0;
|
| +}
|
| +
|
| +static int
|
| +remove_catch_solib (struct bp_location *ignore)
|
| +{
|
| + return 0;
|
| +}
|
| +
|
| +static int
|
| +breakpoint_hit_catch_solib (const struct bp_location *bl,
|
| + struct address_space *aspace,
|
| + CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| +{
|
| + struct solib_catchpoint *self = (struct solib_catchpoint *) bl->owner;
|
| + struct breakpoint *other;
|
| +
|
| + if (ws->kind == TARGET_WAITKIND_LOADED)
|
| + return 1;
|
| +
|
| + ALL_BREAKPOINTS (other)
|
| + {
|
| + struct bp_location *other_bl;
|
| +
|
| + if (other == bl->owner)
|
| + continue;
|
| +
|
| + if (other->type != bp_shlib_event)
|
| + continue;
|
| +
|
| + if (self->base.pspace != NULL && other->pspace != self->base.pspace)
|
| + continue;
|
| +
|
| + for (other_bl = other->loc; other_bl != NULL; other_bl = other_bl->next)
|
| + {
|
| + if (other->ops->breakpoint_hit (other_bl, aspace, bp_addr, ws))
|
| + return 1;
|
| + }
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static void
|
| +check_status_catch_solib (struct bpstats *bs)
|
| +{
|
| + struct solib_catchpoint *self
|
| + = (struct solib_catchpoint *) bs->breakpoint_at;
|
| + int ix;
|
| +
|
| + if (self->is_load)
|
| + {
|
| + struct so_list *iter;
|
| +
|
| + for (ix = 0;
|
| + VEC_iterate (so_list_ptr, current_program_space->added_solibs,
|
| + ix, iter);
|
| + ++ix)
|
| + {
|
| + if (!self->regex
|
| + || regexec (&self->compiled, iter->so_name, 0, NULL, 0) == 0)
|
| + return;
|
| + }
|
| + }
|
| + else
|
| + {
|
| + char *iter;
|
| +
|
| + for (ix = 0;
|
| + VEC_iterate (char_ptr, current_program_space->deleted_solibs,
|
| + ix, iter);
|
| + ++ix)
|
| + {
|
| + if (!self->regex
|
| + || regexec (&self->compiled, iter, 0, NULL, 0) == 0)
|
| + return;
|
| + }
|
| + }
|
| +
|
| + bs->stop = 0;
|
| + bs->print_it = print_it_noop;
|
| +}
|
| +
|
| +static enum print_stop_action
|
| +print_it_catch_solib (bpstat bs)
|
| +{
|
| + struct breakpoint *b = bs->breakpoint_at;
|
| + struct ui_out *uiout = current_uiout;
|
| +
|
| + annotate_catchpoint (b->number);
|
| + if (b->disposition == disp_del)
|
| + ui_out_text (uiout, "\nTemporary catchpoint ");
|
| + else
|
| + ui_out_text (uiout, "\nCatchpoint ");
|
| + ui_out_field_int (uiout, "bkptno", b->number);
|
| + ui_out_text (uiout, "\n");
|
| + if (ui_out_is_mi_like_p (uiout))
|
| + ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
|
| + print_solib_event (1);
|
| + return PRINT_SRC_AND_LOC;
|
| +}
|
| +
|
| +static void
|
| +print_one_catch_solib (struct breakpoint *b, struct bp_location **locs)
|
| +{
|
| + struct solib_catchpoint *self = (struct solib_catchpoint *) b;
|
| + struct value_print_options opts;
|
| + struct ui_out *uiout = current_uiout;
|
| + char *msg;
|
| +
|
| + get_user_print_options (&opts);
|
| + /* Field 4, the address, is omitted (which makes the columns not
|
| + line up too nicely with the headers, but the effect is relatively
|
| + readable). */
|
| + if (opts.addressprint)
|
| + {
|
| + annotate_field (4);
|
| + ui_out_field_skip (uiout, "addr");
|
| + }
|
| +
|
| + annotate_field (5);
|
| + if (self->is_load)
|
| + {
|
| + if (self->regex)
|
| + msg = xstrprintf (_("load of library matching %s"), self->regex);
|
| + else
|
| + msg = xstrdup (_("load of library"));
|
| + }
|
| + else
|
| + {
|
| + if (self->regex)
|
| + msg = xstrprintf (_("unload of library matching %s"), self->regex);
|
| + else
|
| + msg = xstrdup (_("unload of library"));
|
| + }
|
| + ui_out_field_string (uiout, "what", msg);
|
| + xfree (msg);
|
| +}
|
| +
|
| +static void
|
| +print_mention_catch_solib (struct breakpoint *b)
|
| +{
|
| + struct solib_catchpoint *self = (struct solib_catchpoint *) b;
|
| +
|
| + printf_filtered (_("Catchpoint %d (%s)"), b->number,
|
| + self->is_load ? "load" : "unload");
|
| +}
|
| +
|
| +static void
|
| +print_recreate_catch_solib (struct breakpoint *b, struct ui_file *fp)
|
| +{
|
| + struct solib_catchpoint *self = (struct solib_catchpoint *) b;
|
| +
|
| + fprintf_unfiltered (fp, "%s %s",
|
| + b->disposition == disp_del ? "tcatch" : "catch",
|
| + self->is_load ? "load" : "unload");
|
| + if (self->regex)
|
| + fprintf_unfiltered (fp, " %s", self->regex);
|
| + fprintf_unfiltered (fp, "\n");
|
| +}
|
| +
|
| +static struct breakpoint_ops catch_solib_breakpoint_ops;
|
| +
|
| +/* A helper function that does all the work for "catch load" and
|
| + "catch unload". */
|
| +
|
| +static void
|
| +catch_load_or_unload (char *arg, int from_tty, int is_load,
|
| + struct cmd_list_element *command)
|
| +{
|
| + struct solib_catchpoint *c;
|
| + struct gdbarch *gdbarch = get_current_arch ();
|
| + int tempflag;
|
| + struct cleanup *cleanup;
|
| +
|
| + tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
|
| +
|
| + if (!arg)
|
| + arg = "";
|
| + arg = skip_spaces (arg);
|
| +
|
| + c = XCNEW (struct solib_catchpoint);
|
| + cleanup = make_cleanup (xfree, c);
|
| +
|
| + if (*arg != '\0')
|
| + {
|
| + int errcode;
|
| +
|
| + errcode = regcomp (&c->compiled, arg, REG_NOSUB);
|
| + if (errcode != 0)
|
| + {
|
| + char *err = get_regcomp_error (errcode, &c->compiled);
|
| +
|
| + make_cleanup (xfree, err);
|
| + error (_("Invalid regexp (%s): %s"), err, arg);
|
| + }
|
| + c->regex = xstrdup (arg);
|
| }
|
| -}
|
|
|
| -/* Implement the "print_mention" breakpoint_ops method for vfork
|
| - catchpoints. */
|
| + c->is_load = is_load;
|
| + init_catchpoint (&c->base, gdbarch, tempflag, NULL,
|
| + &catch_solib_breakpoint_ops);
|
| +
|
| + discard_cleanups (cleanup);
|
| + install_breakpoint (0, &c->base, 1);
|
| +}
|
|
|
| static void
|
| -print_mention_catch_vfork (struct breakpoint *b)
|
| +catch_load_command_1 (char *arg, int from_tty,
|
| + struct cmd_list_element *command)
|
| {
|
| - printf_filtered (_("Catchpoint %d (vfork)"), b->number);
|
| + catch_load_or_unload (arg, from_tty, 1, command);
|
| }
|
|
|
| -/* Implement the "print_recreate" breakpoint_ops method for vfork
|
| - catchpoints. */
|
| -
|
| static void
|
| -print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp)
|
| +catch_unload_command_1 (char *arg, int from_tty,
|
| + struct cmd_list_element *command)
|
| {
|
| - fprintf_unfiltered (fp, "catch vfork");
|
| - print_recreate_thread (b, fp);
|
| + catch_load_or_unload (arg, from_tty, 0, command);
|
| }
|
|
|
| -/* The breakpoint_ops structure to be used in vfork catchpoints. */
|
| -
|
| -static struct breakpoint_ops catch_vfork_breakpoint_ops;
|
| +DEF_VEC_I(int);
|
|
|
| /* An instance of this type is used to represent a syscall catchpoint.
|
| It includes a "struct breakpoint" as a kind of base class; users
|
| @@ -6439,6 +7914,47 @@ dtor_catch_syscall (struct breakpoint *b)
|
| base_breakpoint_ops.dtor (b);
|
| }
|
|
|
| +static const struct inferior_data *catch_syscall_inferior_data = NULL;
|
| +
|
| +struct catch_syscall_inferior_data
|
| +{
|
| + /* We keep a count of the number of times the user has requested a
|
| + particular syscall to be tracked, and pass this information to the
|
| + target. This lets capable targets implement filtering directly. */
|
| +
|
| + /* Number of times that "any" syscall is requested. */
|
| + int any_syscall_count;
|
| +
|
| + /* Count of each system call. */
|
| + VEC(int) *syscalls_counts;
|
| +
|
| + /* This counts all syscall catch requests, so we can readily determine
|
| + if any catching is necessary. */
|
| + int total_syscalls_count;
|
| +};
|
| +
|
| +static struct catch_syscall_inferior_data*
|
| +get_catch_syscall_inferior_data (struct inferior *inf)
|
| +{
|
| + struct catch_syscall_inferior_data *inf_data;
|
| +
|
| + inf_data = inferior_data (inf, catch_syscall_inferior_data);
|
| + if (inf_data == NULL)
|
| + {
|
| + inf_data = XZALLOC (struct catch_syscall_inferior_data);
|
| + set_inferior_data (inf, catch_syscall_inferior_data, inf_data);
|
| + }
|
| +
|
| + return inf_data;
|
| +}
|
| +
|
| +static void
|
| +catch_syscall_inferior_data_cleanup (struct inferior *inf, void *arg)
|
| +{
|
| + xfree (arg);
|
| +}
|
| +
|
| +
|
| /* Implement the "insert" breakpoint_ops method for syscall
|
| catchpoints. */
|
|
|
| @@ -6447,10 +7963,12 @@ insert_catch_syscall (struct bp_location *bl)
|
| {
|
| struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
|
| struct inferior *inf = current_inferior ();
|
| + struct catch_syscall_inferior_data *inf_data
|
| + = get_catch_syscall_inferior_data (inf);
|
|
|
| - ++inf->total_syscalls_count;
|
| + ++inf_data->total_syscalls_count;
|
| if (!c->syscalls_to_be_caught)
|
| - ++inf->any_syscall_count;
|
| + ++inf_data->any_syscall_count;
|
| else
|
| {
|
| int i, iter;
|
| @@ -6461,28 +7979,31 @@ insert_catch_syscall (struct bp_location *bl)
|
| {
|
| int elem;
|
|
|
| - if (iter >= VEC_length (int, inf->syscalls_counts))
|
| + if (iter >= VEC_length (int, inf_data->syscalls_counts))
|
| {
|
| - int old_size = VEC_length (int, inf->syscalls_counts);
|
| + int old_size = VEC_length (int, inf_data->syscalls_counts);
|
| uintptr_t vec_addr_offset
|
| = old_size * ((uintptr_t) sizeof (int));
|
| uintptr_t vec_addr;
|
| - VEC_safe_grow (int, inf->syscalls_counts, iter + 1);
|
| - vec_addr = (uintptr_t) VEC_address (int, inf->syscalls_counts) +
|
| - vec_addr_offset;
|
| + VEC_safe_grow (int, inf_data->syscalls_counts, iter + 1);
|
| + vec_addr = ((uintptr_t) VEC_address (int,
|
| + inf_data->syscalls_counts)
|
| + + vec_addr_offset);
|
| memset ((void *) vec_addr, 0,
|
| (iter + 1 - old_size) * sizeof (int));
|
| }
|
| - elem = VEC_index (int, inf->syscalls_counts, iter);
|
| - VEC_replace (int, inf->syscalls_counts, iter, ++elem);
|
| + elem = VEC_index (int, inf_data->syscalls_counts, iter);
|
| + VEC_replace (int, inf_data->syscalls_counts, iter, ++elem);
|
| }
|
| }
|
|
|
| return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
|
| - inf->total_syscalls_count != 0,
|
| - inf->any_syscall_count,
|
| - VEC_length (int, inf->syscalls_counts),
|
| - VEC_address (int, inf->syscalls_counts));
|
| + inf_data->total_syscalls_count != 0,
|
| + inf_data->any_syscall_count,
|
| + VEC_length (int,
|
| + inf_data->syscalls_counts),
|
| + VEC_address (int,
|
| + inf_data->syscalls_counts));
|
| }
|
|
|
| /* Implement the "remove" breakpoint_ops method for syscall
|
| @@ -6493,10 +8014,12 @@ remove_catch_syscall (struct bp_location *bl)
|
| {
|
| struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
|
| struct inferior *inf = current_inferior ();
|
| + struct catch_syscall_inferior_data *inf_data
|
| + = get_catch_syscall_inferior_data (inf);
|
|
|
| - --inf->total_syscalls_count;
|
| + --inf_data->total_syscalls_count;
|
| if (!c->syscalls_to_be_caught)
|
| - --inf->any_syscall_count;
|
| + --inf_data->any_syscall_count;
|
| else
|
| {
|
| int i, iter;
|
| @@ -6506,20 +8029,21 @@ remove_catch_syscall (struct bp_location *bl)
|
| i++)
|
| {
|
| int elem;
|
| - if (iter >= VEC_length (int, inf->syscalls_counts))
|
| + if (iter >= VEC_length (int, inf_data->syscalls_counts))
|
| /* Shouldn't happen. */
|
| continue;
|
| - elem = VEC_index (int, inf->syscalls_counts, iter);
|
| - VEC_replace (int, inf->syscalls_counts, iter, --elem);
|
| + elem = VEC_index (int, inf_data->syscalls_counts, iter);
|
| + VEC_replace (int, inf_data->syscalls_counts, iter, --elem);
|
| }
|
| }
|
|
|
| return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
|
| - inf->total_syscalls_count != 0,
|
| - inf->any_syscall_count,
|
| - VEC_length (int, inf->syscalls_counts),
|
| + inf_data->total_syscalls_count != 0,
|
| + inf_data->any_syscall_count,
|
| + VEC_length (int,
|
| + inf_data->syscalls_counts),
|
| VEC_address (int,
|
| - inf->syscalls_counts));
|
| + inf_data->syscalls_counts));
|
| }
|
|
|
| /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
|
| @@ -6527,7 +8051,8 @@ remove_catch_syscall (struct bp_location *bl)
|
|
|
| static int
|
| breakpoint_hit_catch_syscall (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| /* We must check if we are catching specific syscalls in this
|
| breakpoint. If we are, then we must guarantee that the called
|
| @@ -6536,9 +8061,12 @@ breakpoint_hit_catch_syscall (const struct bp_location *bl,
|
| const struct syscall_catchpoint *c
|
| = (const struct syscall_catchpoint *) bl->owner;
|
|
|
| - if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
|
| + if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY
|
| + && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN)
|
| return 0;
|
|
|
| + syscall_number = ws->value.syscall_number;
|
| +
|
| /* Now, checking if the syscall is the same. */
|
| if (c->syscalls_to_be_caught)
|
| {
|
| @@ -6572,7 +8100,6 @@ print_it_catch_syscall (bpstat bs)
|
| ptid_t ptid;
|
| struct target_waitstatus last;
|
| struct syscall s;
|
| - char *syscall_id;
|
|
|
| get_last_target_status (&ptid, &last);
|
|
|
| @@ -6839,11 +8366,16 @@ remove_catch_exec (struct bp_location *bl)
|
|
|
| static int
|
| breakpoint_hit_catch_exec (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct exec_catchpoint *c = (struct exec_catchpoint *) bl->owner;
|
|
|
| - return inferior_has_execd (inferior_ptid, &c->exec_pathname);
|
| + if (ws->kind != TARGET_WAITKIND_EXECD)
|
| + return 0;
|
| +
|
| + c->exec_pathname = xstrdup (ws->value.execd_pathname);
|
| + return 1;
|
| }
|
|
|
| static enum print_stop_action
|
| @@ -7095,6 +8627,7 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
|
| copy->loc->address = orig->loc->address;
|
| copy->loc->section = orig->loc->section;
|
| copy->loc->pspace = orig->loc->pspace;
|
| + copy->loc->probe = orig->loc->probe;
|
|
|
| if (orig->loc->source_file != NULL)
|
| copy->loc->source_file = xstrdup (orig->loc->source_file);
|
| @@ -7180,6 +8713,7 @@ add_location_to_breakpoint (struct breakpoint *b,
|
| loc->requested_address = sal->pc;
|
| loc->address = adjusted_address;
|
| loc->pspace = sal->pspace;
|
| + loc->probe = sal->probe;
|
| gdb_assert (loc->pspace != NULL);
|
| loc->section = sal->section;
|
| loc->gdbarch = loc_gdbarch;
|
| @@ -7235,7 +8769,101 @@ bp_loc_is_permanent (struct bp_location *loc)
|
| return retval;
|
| }
|
|
|
| +/* Build a command list for the dprintf corresponding to the current
|
| + settings of the dprintf style options. */
|
| +
|
| +static void
|
| +update_dprintf_command_list (struct breakpoint *b)
|
| +{
|
| + char *dprintf_args = b->extra_string;
|
| + char *printf_line = NULL;
|
| +
|
| + if (!dprintf_args)
|
| + return;
|
| +
|
| + dprintf_args = skip_spaces (dprintf_args);
|
| +
|
| + /* Allow a comma, as it may have terminated a location, but don't
|
| + insist on it. */
|
| + if (*dprintf_args == ',')
|
| + ++dprintf_args;
|
| + dprintf_args = skip_spaces (dprintf_args);
|
| +
|
| + if (*dprintf_args != '"')
|
| + error (_("Bad format string, missing '\"'."));
|
| +
|
| + if (strcmp (dprintf_style, dprintf_style_gdb) == 0)
|
| + printf_line = xstrprintf ("printf %s", dprintf_args);
|
| + else if (strcmp (dprintf_style, dprintf_style_call) == 0)
|
| + {
|
| + if (!dprintf_function)
|
| + error (_("No function supplied for dprintf call"));
|
| +
|
| + if (dprintf_channel && strlen (dprintf_channel) > 0)
|
| + printf_line = xstrprintf ("call (void) %s (%s,%s)",
|
| + dprintf_function,
|
| + dprintf_channel,
|
| + dprintf_args);
|
| + else
|
| + printf_line = xstrprintf ("call (void) %s (%s)",
|
| + dprintf_function,
|
| + dprintf_args);
|
| + }
|
| + else if (strcmp (dprintf_style, dprintf_style_agent) == 0)
|
| + {
|
| + if (target_can_run_breakpoint_commands ())
|
| + printf_line = xstrprintf ("agent-printf %s", dprintf_args);
|
| + else
|
| + {
|
| + warning (_("Target cannot run dprintf commands, falling back to GDB printf"));
|
| + printf_line = xstrprintf ("printf %s", dprintf_args);
|
| + }
|
| + }
|
| + else
|
| + internal_error (__FILE__, __LINE__,
|
| + _("Invalid dprintf style."));
|
| +
|
| + /* Manufacture a printf/continue sequence. */
|
| + if (printf_line)
|
| + {
|
| + struct command_line *printf_cmd_line, *cont_cmd_line = NULL;
|
| +
|
| + if (strcmp (dprintf_style, dprintf_style_agent) != 0)
|
| + {
|
| + cont_cmd_line = xmalloc (sizeof (struct command_line));
|
| + cont_cmd_line->control_type = simple_control;
|
| + cont_cmd_line->body_count = 0;
|
| + cont_cmd_line->body_list = NULL;
|
| + cont_cmd_line->next = NULL;
|
| + cont_cmd_line->line = xstrdup ("continue");
|
| + }
|
| +
|
| + printf_cmd_line = xmalloc (sizeof (struct command_line));
|
| + printf_cmd_line->control_type = simple_control;
|
| + printf_cmd_line->body_count = 0;
|
| + printf_cmd_line->body_list = NULL;
|
| + printf_cmd_line->next = cont_cmd_line;
|
| + printf_cmd_line->line = printf_line;
|
| +
|
| + breakpoint_set_commands (b, printf_cmd_line);
|
| + }
|
| +}
|
| +
|
| +/* Update all dprintf commands, making their command lists reflect
|
| + current style settings. */
|
|
|
| +static void
|
| +update_dprintf_commands (char *args, int from_tty,
|
| + struct cmd_list_element *c)
|
| +{
|
| + struct breakpoint *b;
|
| +
|
| + ALL_BREAKPOINTS (b)
|
| + {
|
| + if (b->type == bp_dprintf)
|
| + update_dprintf_command_list (b);
|
| + }
|
| +}
|
|
|
| /* Create a breakpoint with SAL as location. Use ADDR_STRING
|
| as textual description of the location, and COND_STRING
|
| @@ -7245,10 +8873,11 @@ static void
|
| init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
|
| struct symtabs_and_lines sals, char *addr_string,
|
| char *filter, char *cond_string,
|
| + char *extra_string,
|
| enum bptype type, enum bpdisp disposition,
|
| int thread, int task, int ignore_count,
|
| const struct breakpoint_ops *ops, int from_tty,
|
| - int enabled, int internal, unsigned flags,
|
| + int enabled, int internal, unsigned flags,
|
| int display_canonical)
|
| {
|
| int i;
|
| @@ -7289,8 +8918,9 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
|
| init_raw_breakpoint (b, gdbarch, sal, type, ops);
|
| b->thread = thread;
|
| b->task = task;
|
| -
|
| +
|
| b->cond_string = cond_string;
|
| + b->extra_string = extra_string;
|
| b->ignore_count = ignore_count;
|
| b->enable_state = enabled ? bp_enabled : bp_disabled;
|
| b->disposition = disposition;
|
| @@ -7303,7 +8933,7 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
|
| struct tracepoint *t = (struct tracepoint *) b;
|
| struct static_tracepoint_marker marker;
|
|
|
| - if (is_marker_spec (addr_string))
|
| + if (strace_marker_p (b))
|
| {
|
| /* We already know the marker exists, otherwise, we
|
| wouldn't see a sal for it. */
|
| @@ -7351,11 +8981,24 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
|
| if (b->cond_string)
|
| {
|
| char *arg = b->cond_string;
|
| - loc->cond = parse_exp_1 (&arg, block_for_pc (loc->address), 0);
|
| + loc->cond = parse_exp_1 (&arg, loc->address,
|
| + block_for_pc (loc->address), 0);
|
| if (*arg)
|
| - error (_("Garbage %s follows condition"), arg);
|
| + error (_("Garbage '%s' follows condition"), arg);
|
| + }
|
| +
|
| + /* Dynamic printf requires and uses additional arguments on the
|
| + command line, otherwise it's an error. */
|
| + if (type == bp_dprintf)
|
| + {
|
| + if (b->extra_string)
|
| + update_dprintf_command_list (b);
|
| + else
|
| + error (_("Format string required"));
|
| }
|
| - }
|
| + else if (b->extra_string)
|
| + error (_("Garbage '%s' at end of command"), b->extra_string);
|
| + }
|
|
|
| b->display_canonical = display_canonical;
|
| if (addr_string)
|
| @@ -7372,6 +9015,7 @@ static void
|
| create_breakpoint_sal (struct gdbarch *gdbarch,
|
| struct symtabs_and_lines sals, char *addr_string,
|
| char *filter, char *cond_string,
|
| + char *extra_string,
|
| enum bptype type, enum bpdisp disposition,
|
| int thread, int task, int ignore_count,
|
| const struct breakpoint_ops *ops, int from_tty,
|
| @@ -7395,7 +9039,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
|
|
|
| init_breakpoint_sal (b, gdbarch,
|
| sals, addr_string,
|
| - filter, cond_string,
|
| + filter, cond_string, extra_string,
|
| type, disposition,
|
| thread, task, ignore_count,
|
| ops, from_tty,
|
| @@ -7424,7 +9068,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
|
| static void
|
| create_breakpoints_sal (struct gdbarch *gdbarch,
|
| struct linespec_result *canonical,
|
| - char *cond_string,
|
| + char *cond_string, char *extra_string,
|
| enum bptype type, enum bpdisp disposition,
|
| int thread, int task, int ignore_count,
|
| const struct breakpoint_ops *ops, int from_tty,
|
| @@ -7450,7 +9094,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
|
| create_breakpoint_sal (gdbarch, lsal->sals,
|
| addr_string,
|
| filter_string,
|
| - cond_string, type, disposition,
|
| + cond_string, extra_string,
|
| + type, disposition,
|
| thread, task, ignore_count, ops,
|
| from_tty, enabled, internal, flags,
|
| canonical->special_display);
|
| @@ -7511,19 +9156,26 @@ parse_breakpoint_sals (char **address,
|
| }
|
| else
|
| {
|
| + struct symtab_and_line cursal = get_current_source_symtab_and_line ();
|
| +
|
| /* Force almost all breakpoints to be in terms of the
|
| current_source_symtab (which is decode_line_1's default).
|
| This should produce the results we want almost all of the
|
| - time while leaving default_breakpoint_* alone. */
|
| - if (last_displayed_sal_is_valid ())
|
| + time while leaving default_breakpoint_* alone.
|
| +
|
| + ObjC: However, don't match an Objective-C method name which
|
| + may have a '+' or '-' succeeded by a '['. */
|
| + if (last_displayed_sal_is_valid ()
|
| + && (!cursal.symtab
|
| + || ((strchr ("+-", (*address)[0]) != NULL)
|
| + && ((*address)[1] != '['))))
|
| decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
|
| get_last_displayed_symtab (),
|
| get_last_displayed_line (),
|
| canonical, NULL, NULL);
|
| else
|
| decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
|
| - (struct symtab *) NULL, 0,
|
| - canonical, NULL, NULL);
|
| + cursal.symtab, cursal.line, canonical, NULL, NULL);
|
| }
|
| }
|
|
|
| @@ -7585,9 +9237,11 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
|
| PC identifies the context at which the condition should be parsed.
|
| If no condition is found, *COND_STRING is set to NULL.
|
| If no thread is found, *THREAD is set to -1. */
|
| -static void
|
| -find_condition_and_thread (char *tok, CORE_ADDR pc,
|
| - char **cond_string, int *thread, int *task)
|
| +
|
| +static void
|
| +find_condition_and_thread (char *tok, CORE_ADDR pc,
|
| + char **cond_string, int *thread, int *task,
|
| + char **rest)
|
| {
|
| *cond_string = NULL;
|
| *thread = -1;
|
| @@ -7599,26 +9253,31 @@ find_condition_and_thread (char *tok, CORE_ADDR pc,
|
| char *cond_end = NULL;
|
|
|
| tok = skip_spaces (tok);
|
| -
|
| +
|
| + if ((*tok == '"' || *tok == ',') && rest)
|
| + {
|
| + *rest = savestring (tok, strlen (tok));
|
| + return;
|
| + }
|
| +
|
| end_tok = skip_to_space (tok);
|
| -
|
| +
|
| toklen = end_tok - tok;
|
| -
|
| +
|
| if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
|
| {
|
| struct expression *expr;
|
|
|
| tok = cond_start = end_tok + 1;
|
| - expr = parse_exp_1 (&tok, block_for_pc (pc), 0);
|
| + expr = parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
|
| xfree (expr);
|
| cond_end = tok;
|
| - *cond_string = savestring (cond_start,
|
| - cond_end - cond_start);
|
| + *cond_string = savestring (cond_start, cond_end - cond_start);
|
| }
|
| else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
|
| {
|
| char *tmptok;
|
| -
|
| +
|
| tok = end_tok + 1;
|
| tmptok = tok;
|
| *thread = strtol (tok, &tok, 0);
|
| @@ -7639,6 +9298,11 @@ find_condition_and_thread (char *tok, CORE_ADDR pc,
|
| if (!valid_task_id (*task))
|
| error (_("Unknown task %d."), *task);
|
| }
|
| + else if (rest)
|
| + {
|
| + *rest = savestring (tok, strlen (tok));
|
| + return;
|
| + }
|
| else
|
| error (_("Junk at end of arguments."));
|
| }
|
| @@ -7651,8 +9315,6 @@ decode_static_tracepoint_spec (char **arg_p)
|
| {
|
| VEC(static_tracepoint_marker_p) *markers = NULL;
|
| struct symtabs_and_lines sals;
|
| - struct symtab_and_line sal;
|
| - struct symbol *sym;
|
| struct cleanup *old_chain;
|
| char *p = &(*arg_p)[3];
|
| char *endp;
|
| @@ -7706,7 +9368,8 @@ decode_static_tracepoint_spec (char **arg_p)
|
|
|
| int
|
| create_breakpoint (struct gdbarch *gdbarch,
|
| - char *arg, char *cond_string, int thread,
|
| + char *arg, char *cond_string,
|
| + int thread, char *extra_string,
|
| int parse_condition_and_thread,
|
| int tempflag, enum bptype type_wanted,
|
| int ignore_count,
|
| @@ -7721,7 +9384,6 @@ create_breakpoint (struct gdbarch *gdbarch,
|
| struct linespec_result canonical;
|
| struct cleanup *old_chain;
|
| struct cleanup *bkpt_chain = NULL;
|
| - int i;
|
| int pending = 0;
|
| int task = 0;
|
| int prev_bkpt_count = breakpoint_count;
|
| @@ -7730,32 +9392,19 @@ create_breakpoint (struct gdbarch *gdbarch,
|
|
|
| init_linespec_result (&canonical);
|
|
|
| - if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
|
| - {
|
| - int i;
|
| - struct linespec_sals lsal;
|
| -
|
| - lsal.sals = decode_static_tracepoint_spec (&arg);
|
| -
|
| - copy_arg = savestring (addr_start, arg - addr_start);
|
| -
|
| - canonical.addr_string = xstrdup (copy_arg);
|
| - lsal.canonical = xstrdup (copy_arg);
|
| - VEC_safe_push (linespec_sals, canonical.sals, &lsal);
|
| -
|
| - goto done;
|
| - }
|
| -
|
| TRY_CATCH (e, RETURN_MASK_ALL)
|
| {
|
| - parse_breakpoint_sals (&arg, &canonical);
|
| + ops->create_sals_from_address (&arg, &canonical, type_wanted,
|
| + addr_start, ©_arg);
|
| }
|
|
|
| /* If caller is interested in rc value from parse, set value. */
|
| switch (e.reason)
|
| {
|
| - case RETURN_QUIT:
|
| - throw_exception (e);
|
| + case GDB_NO_ERROR:
|
| + if (VEC_empty (linespec_sals, canonical.sals))
|
| + return 0;
|
| + break;
|
| case RETURN_ERROR:
|
| switch (e.error)
|
| {
|
| @@ -7797,12 +9446,9 @@ create_breakpoint (struct gdbarch *gdbarch,
|
| }
|
| break;
|
| default:
|
| - if (VEC_empty (linespec_sals, canonical.sals))
|
| - return 0;
|
| + throw_exception (e);
|
| }
|
|
|
| - done:
|
| -
|
| /* Create a chain of things that always need to be cleaned up. */
|
| old_chain = make_cleanup_destroy_linespec_result (&canonical);
|
|
|
| @@ -7844,16 +9490,22 @@ create_breakpoint (struct gdbarch *gdbarch,
|
|
|
| if (parse_condition_and_thread)
|
| {
|
| + char *rest;
|
| /* Here we only parse 'arg' to separate condition
|
| from thread number, so parsing in context of first
|
| sal is OK. When setting the breakpoint we'll
|
| re-parse it in context of each sal. */
|
| cond_string = NULL;
|
| thread = -1;
|
| + rest = NULL;
|
| find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
|
| - &thread, &task);
|
| + &thread, &task, &rest);
|
| if (cond_string)
|
| make_cleanup (xfree, cond_string);
|
| + if (rest)
|
| + make_cleanup (xfree, rest);
|
| + if (rest)
|
| + extra_string = rest;
|
| }
|
| else
|
| {
|
| @@ -7863,59 +9515,19 @@ create_breakpoint (struct gdbarch *gdbarch,
|
| cond_string = xstrdup (cond_string);
|
| make_cleanup (xfree, cond_string);
|
| }
|
| + /* Create a private copy of any extra string. */
|
| + if (extra_string)
|
| + {
|
| + extra_string = xstrdup (extra_string);
|
| + make_cleanup (xfree, extra_string);
|
| + }
|
| }
|
|
|
| - /* If the user is creating a static tracepoint by marker id
|
| - (strace -m MARKER_ID), then store the sals index, so that
|
| - breakpoint_re_set can try to match up which of the newly
|
| - found markers corresponds to this one, and, don't try to
|
| - expand multiple locations for each sal, given than SALS
|
| - already should contain all sals for MARKER_ID. */
|
| - if (type_wanted == bp_static_tracepoint
|
| - && is_marker_spec (copy_arg))
|
| - {
|
| - int i;
|
| -
|
| - for (i = 0; i < lsal->sals.nelts; ++i)
|
| - {
|
| - struct symtabs_and_lines expanded;
|
| - struct tracepoint *tp;
|
| - struct cleanup *old_chain;
|
| - char *addr_string;
|
| -
|
| - expanded.nelts = 1;
|
| - expanded.sals = &lsal->sals.sals[i];
|
| -
|
| - addr_string = xstrdup (canonical.addr_string);
|
| - old_chain = make_cleanup (xfree, addr_string);
|
| -
|
| - tp = XCNEW (struct tracepoint);
|
| - init_breakpoint_sal (&tp->base, gdbarch, expanded,
|
| - addr_string, NULL,
|
| - cond_string, type_wanted,
|
| + ops->create_breakpoints_sal (gdbarch, &canonical, lsal,
|
| + cond_string, extra_string, type_wanted,
|
| tempflag ? disp_del : disp_donttouch,
|
| thread, task, ignore_count, ops,
|
| - from_tty, enabled, internal, flags,
|
| - canonical.special_display);
|
| - /* Given that its possible to have multiple markers with
|
| - the same string id, if the user is creating a static
|
| - tracepoint by marker id ("strace -m MARKER_ID"), then
|
| - store the sals index, so that breakpoint_re_set can
|
| - try to match up which of the newly found markers
|
| - corresponds to this one */
|
| - tp->static_trace_marker_id_idx = i;
|
| -
|
| - install_breakpoint (internal, &tp->base, 0);
|
| -
|
| - discard_cleanups (old_chain);
|
| - }
|
| - }
|
| - else
|
| - create_breakpoints_sal (gdbarch, &canonical, cond_string,
|
| - type_wanted,
|
| - tempflag ? disp_del : disp_donttouch,
|
| - thread, task, ignore_count, ops, from_tty,
|
| - enabled, internal, flags);
|
| + from_tty, enabled, internal, flags);
|
| }
|
| else
|
| {
|
| @@ -7936,7 +9548,19 @@ create_breakpoint (struct gdbarch *gdbarch,
|
| init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
|
|
|
| b->addr_string = copy_arg;
|
| - b->cond_string = NULL;
|
| + if (parse_condition_and_thread)
|
| + b->cond_string = NULL;
|
| + else
|
| + {
|
| + /* Create a private copy of condition string. */
|
| + if (cond_string)
|
| + {
|
| + cond_string = xstrdup (cond_string);
|
| + make_cleanup (xfree, cond_string);
|
| + }
|
| + b->cond_string = cond_string;
|
| + }
|
| + b->extra_string = NULL;
|
| b->ignore_count = ignore_count;
|
| b->disposition = tempflag ? disp_del : disp_donttouch;
|
| b->condition_not_parsed = 1;
|
| @@ -7981,14 +9605,22 @@ break_command_1 (char *arg, int flag, int from_tty)
|
| enum bptype type_wanted = (flag & BP_HARDWAREFLAG
|
| ? bp_hardware_breakpoint
|
| : bp_breakpoint);
|
| + struct breakpoint_ops *ops;
|
| + const char *arg_cp = arg;
|
| +
|
| + /* Matching breakpoints on probes. */
|
| + if (arg && probe_linespec_to_ops (&arg_cp) != NULL)
|
| + ops = &bkpt_probe_breakpoint_ops;
|
| + else
|
| + ops = &bkpt_breakpoint_ops;
|
|
|
| create_breakpoint (get_current_arch (),
|
| arg,
|
| - NULL, 0, 1 /* parse arg */,
|
| + NULL, 0, NULL, 1 /* parse arg */,
|
| tempflag, type_wanted,
|
| 0 /* Ignore count */,
|
| pending_break_support,
|
| - &bkpt_breakpoint_ops,
|
| + ops,
|
| from_tty,
|
| 1 /* enabled */,
|
| 0 /* internal */,
|
| @@ -8149,14 +9781,48 @@ stopat_command (char *arg, int from_tty)
|
| break_command_1 (arg, 0, from_tty);
|
| }
|
|
|
| +void dprintf_command (char *arg, int from_tty);
|
| +
|
| +/* The dynamic printf command is mostly like a regular breakpoint, but
|
| + with a prewired command list consisting of a single output command,
|
| + built from extra arguments supplied on the dprintf command
|
| + line. */
|
| +
|
| +void
|
| +dprintf_command (char *arg, int from_tty)
|
| +{
|
| + create_breakpoint (get_current_arch (),
|
| + arg,
|
| + NULL, 0, NULL, 1 /* parse arg */,
|
| + 0, bp_dprintf,
|
| + 0 /* Ignore count */,
|
| + pending_break_support,
|
| + &dprintf_breakpoint_ops,
|
| + from_tty,
|
| + 1 /* enabled */,
|
| + 0 /* internal */,
|
| + 0);
|
| +}
|
| +
|
| +static void
|
| +agent_printf_command (char *arg, int from_tty)
|
| +{
|
| + error (_("May only run agent-printf on the target"));
|
| +}
|
| +
|
| /* Implement the "breakpoint_hit" breakpoint_ops method for
|
| ranged breakpoints. */
|
|
|
| static int
|
| breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
|
| struct address_space *aspace,
|
| - CORE_ADDR bp_addr)
|
| + CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| + if (ws->kind != TARGET_WAITKIND_STOPPED
|
| + || ws->value.sig != GDB_SIGNAL_TRAP)
|
| + return 0;
|
| +
|
| return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
|
| bl->length, aspace, bp_addr);
|
| }
|
| @@ -8236,8 +9902,8 @@ print_one_detail_ranged_breakpoint (const struct breakpoint *b,
|
| {
|
| CORE_ADDR address_start, address_end;
|
| struct bp_location *bl = b->loc;
|
| - struct ui_stream *stb = ui_out_stream_new (uiout);
|
| - struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
|
| + struct ui_file *stb = mem_fileopen ();
|
| + struct cleanup *cleanup = make_cleanup_ui_file_delete (stb);
|
|
|
| gdb_assert (bl);
|
|
|
| @@ -8245,7 +9911,7 @@ print_one_detail_ranged_breakpoint (const struct breakpoint *b,
|
| address_end = address_start + bl->length - 1;
|
|
|
| ui_out_text (uiout, "\taddress range: ");
|
| - fprintf_unfiltered (stb->stream, "[%s, %s]",
|
| + fprintf_unfiltered (stb, "[%s, %s]",
|
| print_core_address (bl->gdbarch, address_start),
|
| print_core_address (bl->gdbarch, address_end));
|
| ui_out_field_stream (uiout, "addr", stb);
|
| @@ -8441,6 +10107,7 @@ break_range_command (char *arg, int from_tty)
|
| means EXP is variable. Also the constant detection may fail for
|
| some constant expressions and in such case still falsely return
|
| zero. */
|
| +
|
| static int
|
| watchpoint_exp_is_const (const struct expression *exp)
|
| {
|
| @@ -8505,6 +10172,7 @@ watchpoint_exp_is_const (const struct expression *exp)
|
| case UNOP_COMPLEMENT:
|
| case UNOP_ADDR:
|
| case UNOP_HIGH:
|
| + case UNOP_CAST:
|
| /* Unary, binary and ternary operators: We have to check
|
| their operands. If they are constant, then so is the
|
| result of that operation. For instance, if A and B are
|
| @@ -8623,7 +10291,8 @@ remove_watchpoint (struct bp_location *bl)
|
|
|
| static int
|
| breakpoint_hit_watchpoint (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct breakpoint *b = bl->owner;
|
| struct watchpoint *w = (struct watchpoint *) b;
|
| @@ -8677,7 +10346,7 @@ print_it_watchpoint (bpstat bs)
|
| struct cleanup *old_chain;
|
| struct breakpoint *b;
|
| const struct bp_location *bl;
|
| - struct ui_stream *stb;
|
| + struct ui_file *stb;
|
| enum print_stop_action result;
|
| struct watchpoint *w;
|
| struct ui_out *uiout = current_uiout;
|
| @@ -8688,8 +10357,8 @@ print_it_watchpoint (bpstat bs)
|
| b = bs->breakpoint_at;
|
| w = (struct watchpoint *) b;
|
|
|
| - stb = ui_out_stream_new (uiout);
|
| - old_chain = make_cleanup_ui_out_stream_delete (stb);
|
| + stb = mem_fileopen ();
|
| + old_chain = make_cleanup_ui_file_delete (stb);
|
|
|
| switch (b->type)
|
| {
|
| @@ -8703,10 +10372,10 @@ print_it_watchpoint (bpstat bs)
|
| mention (b);
|
| make_cleanup_ui_out_tuple_begin_end (uiout, "value");
|
| ui_out_text (uiout, "\nOld value = ");
|
| - watchpoint_value_print (bs->old_val, stb->stream);
|
| + watchpoint_value_print (bs->old_val, stb);
|
| ui_out_field_stream (uiout, "old", stb);
|
| ui_out_text (uiout, "\nNew value = ");
|
| - watchpoint_value_print (w->val, stb->stream);
|
| + watchpoint_value_print (w->val, stb);
|
| ui_out_field_stream (uiout, "new", stb);
|
| ui_out_text (uiout, "\n");
|
| /* More than one watchpoint may have been triggered. */
|
| @@ -8721,7 +10390,7 @@ print_it_watchpoint (bpstat bs)
|
| mention (b);
|
| make_cleanup_ui_out_tuple_begin_end (uiout, "value");
|
| ui_out_text (uiout, "\nValue = ");
|
| - watchpoint_value_print (w->val, stb->stream);
|
| + watchpoint_value_print (w->val, stb);
|
| ui_out_field_stream (uiout, "value", stb);
|
| ui_out_text (uiout, "\n");
|
| result = PRINT_UNKNOWN;
|
| @@ -8738,7 +10407,7 @@ print_it_watchpoint (bpstat bs)
|
| mention (b);
|
| make_cleanup_ui_out_tuple_begin_end (uiout, "value");
|
| ui_out_text (uiout, "\nOld value = ");
|
| - watchpoint_value_print (bs->old_val, stb->stream);
|
| + watchpoint_value_print (bs->old_val, stb);
|
| ui_out_field_stream (uiout, "old", stb);
|
| ui_out_text (uiout, "\nNew value = ");
|
| }
|
| @@ -8752,7 +10421,7 @@ print_it_watchpoint (bpstat bs)
|
| make_cleanup_ui_out_tuple_begin_end (uiout, "value");
|
| ui_out_text (uiout, "\nValue = ");
|
| }
|
| - watchpoint_value_print (w->val, stb->stream);
|
| + watchpoint_value_print (w->val, stb);
|
| ui_out_field_stream (uiout, "new", stb);
|
| ui_out_text (uiout, "\n");
|
| result = PRINT_UNKNOWN;
|
| @@ -9137,7 +10806,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
|
| /* Parse the rest of the arguments. */
|
| innermost_block = NULL;
|
| exp_start = arg;
|
| - exp = parse_exp_1 (&arg, 0, 0);
|
| + exp = parse_exp_1 (&arg, 0, 0, 0);
|
| exp_end = arg;
|
| /* Remove trailing whitespace from the expression before saving it.
|
| This makes the eventual display of the expression string a bit
|
| @@ -9192,7 +10861,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
|
|
|
| innermost_block = NULL;
|
| tok = cond_start = end_tok + 1;
|
| - cond = parse_exp_1 (&tok, 0, 0);
|
| + cond = parse_exp_1 (&tok, 0, 0, 0);
|
|
|
| /* The watchpoint expression may not be local, but the condition
|
| may still be. E.g.: `watch global if local > 0'. */
|
| @@ -9427,23 +11096,6 @@ watch_command_wrapper (char *arg, int from_tty, int internal)
|
| watch_command_1 (arg, hw_write, from_tty, 0, internal);
|
| }
|
|
|
| -/* A helper function that looks for an argument at the start of a
|
| - string. The argument must also either be at the end of the string,
|
| - or be followed by whitespace. Returns 1 if it finds the argument,
|
| - 0 otherwise. If the argument is found, it updates *STR. */
|
| -
|
| -static int
|
| -check_for_argument (char **str, char *arg, int arg_len)
|
| -{
|
| - if (strncmp (*str, arg, arg_len) == 0
|
| - && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
|
| - {
|
| - *str += arg_len;
|
| - return 1;
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| /* A helper function that looks for the "-location" argument and then
|
| calls watch_command_1. */
|
|
|
| @@ -9524,7 +11176,10 @@ until_break_command (char *arg, int from_tty, int anywhere)
|
| {
|
| struct symtabs_and_lines sals;
|
| struct symtab_and_line sal;
|
| - struct frame_info *frame = get_selected_frame (NULL);
|
| + struct frame_info *frame;
|
| + struct gdbarch *frame_gdbarch;
|
| + struct frame_id stack_frame_id;
|
| + struct frame_id caller_frame_id;
|
| struct breakpoint *breakpoint;
|
| struct breakpoint *breakpoint2 = NULL;
|
| struct cleanup *old_chain;
|
| @@ -9555,41 +11210,56 @@ until_break_command (char *arg, int from_tty, int anywhere)
|
|
|
| resolve_sal_pc (&sal);
|
|
|
| - if (anywhere)
|
| - /* If the user told us to continue until a specified location,
|
| - we don't specify a frame at which we need to stop. */
|
| - breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
|
| - null_frame_id, bp_until);
|
| - else
|
| - /* Otherwise, specify the selected frame, because we want to stop
|
| - only at the very same frame. */
|
| - breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
|
| - get_stack_frame_id (frame),
|
| - bp_until);
|
| -
|
| - old_chain = make_cleanup_delete_breakpoint (breakpoint);
|
| -
|
| tp = inferior_thread ();
|
| thread = tp->num;
|
|
|
| + old_chain = make_cleanup (null_cleanup, NULL);
|
| +
|
| + /* Note linespec handling above invalidates the frame chain.
|
| + Installing a breakpoint also invalidates the frame chain (as it
|
| + may need to switch threads), so do any frame handling before
|
| + that. */
|
| +
|
| + frame = get_selected_frame (NULL);
|
| + frame_gdbarch = get_frame_arch (frame);
|
| + stack_frame_id = get_stack_frame_id (frame);
|
| + caller_frame_id = frame_unwind_caller_id (frame);
|
| +
|
| /* Keep within the current frame, or in frames called by the current
|
| one. */
|
|
|
| - if (frame_id_p (frame_unwind_caller_id (frame)))
|
| + if (frame_id_p (caller_frame_id))
|
| {
|
| - sal = find_pc_line (frame_unwind_caller_pc (frame), 0);
|
| - sal.pc = frame_unwind_caller_pc (frame);
|
| + struct symtab_and_line sal2;
|
| +
|
| + sal2 = find_pc_line (frame_unwind_caller_pc (frame), 0);
|
| + sal2.pc = frame_unwind_caller_pc (frame);
|
| breakpoint2 = set_momentary_breakpoint (frame_unwind_caller_arch (frame),
|
| - sal,
|
| - frame_unwind_caller_id (frame),
|
| + sal2,
|
| + caller_frame_id,
|
| bp_until);
|
| make_cleanup_delete_breakpoint (breakpoint2);
|
|
|
| - set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame));
|
| + set_longjmp_breakpoint (tp, caller_frame_id);
|
| make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
|
| }
|
|
|
| - proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
|
| + /* set_momentary_breakpoint could invalidate FRAME. */
|
| + frame = NULL;
|
| +
|
| + if (anywhere)
|
| + /* If the user told us to continue until a specified location,
|
| + we don't specify a frame at which we need to stop. */
|
| + breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
|
| + null_frame_id, bp_until);
|
| + else
|
| + /* Otherwise, specify the selected frame, because we want to stop
|
| + only at the very same frame. */
|
| + breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
|
| + stack_frame_id, bp_until);
|
| + make_cleanup_delete_breakpoint (breakpoint);
|
| +
|
| + proceed (-1, GDB_SIGNAL_DEFAULT, 0);
|
|
|
| /* If we are running asynchronously, and proceed call above has
|
| actually managed to start the target, arrange for breakpoints to
|
| @@ -9841,7 +11511,7 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_string,
|
| trigger_func_name = "__cxa_throw";
|
|
|
| create_breakpoint (get_current_arch (),
|
| - trigger_func_name, cond_string, -1,
|
| + trigger_func_name, cond_string, -1, NULL,
|
| 0 /* condition and thread are valid. */,
|
| tempflag, bp_breakpoint,
|
| 0,
|
| @@ -10077,8 +11747,9 @@ clear_command (char *arg, int from_tty)
|
|
|
| if (arg)
|
| {
|
| - sals = decode_line_spec (arg, (DECODE_LINE_FUNFIRSTLINE
|
| - | DECODE_LINE_LIST_MODE));
|
| + sals = decode_line_with_current_source (arg,
|
| + (DECODE_LINE_FUNFIRSTLINE
|
| + | DECODE_LINE_LIST_MODE));
|
| default_match = 0;
|
| }
|
| else
|
| @@ -10127,6 +11798,8 @@ clear_command (char *arg, int from_tty)
|
| make_cleanup (VEC_cleanup (breakpoint_p), &found);
|
| for (i = 0; i < sals.nelts; i++)
|
| {
|
| + int is_abs, sal_name_len;
|
| +
|
| /* If exact pc given, clear bpts at that pc.
|
| If line given (pc == 0), clear all bpts on specified line.
|
| If defaulting, clear all bpts on default line
|
| @@ -10140,6 +11813,8 @@ clear_command (char *arg, int from_tty)
|
| 1 0 <can't happen> */
|
|
|
| sal = sals.sals[i];
|
| + is_abs = sal.symtab == NULL ? 1 : IS_ABSOLUTE_PATH (sal.symtab->filename);
|
| + sal_name_len = is_abs ? 0 : strlen (sal.symtab->filename);
|
|
|
| /* Find all matching breakpoints and add them to 'found'. */
|
| ALL_BREAKPOINTS (b)
|
| @@ -10159,13 +11834,24 @@ clear_command (char *arg, int from_tty)
|
| && (loc->address == sal.pc)
|
| && (!section_is_overlay (loc->section)
|
| || loc->section == sal.section));
|
| - int line_match = ((default_match || sal.explicit_line)
|
| - && loc->source_file != NULL
|
| - && sal.symtab != NULL
|
| - && sal.pspace == loc->pspace
|
| - && filename_cmp (loc->source_file,
|
| - sal.symtab->filename) == 0
|
| - && loc->line_number == sal.line);
|
| + int line_match = 0;
|
| +
|
| + if ((default_match || sal.explicit_line)
|
| + && loc->source_file != NULL
|
| + && sal.symtab != NULL
|
| + && sal.pspace == loc->pspace
|
| + && loc->line_number == sal.line)
|
| + {
|
| + if (filename_cmp (loc->source_file,
|
| + sal.symtab->filename) == 0)
|
| + line_match = 1;
|
| + else if (!IS_ABSOLUTE_PATH (sal.symtab->filename)
|
| + && compare_filenames_for_search (loc->source_file,
|
| + sal.symtab->filename,
|
| + sal_name_len))
|
| + line_match = 1;
|
| + }
|
| +
|
| if (pc_match || line_match)
|
| {
|
| match = 1;
|
| @@ -10267,16 +11953,25 @@ bp_location_compare (const void *ap, const void *bp)
|
| if (a->address != b->address)
|
| return (a->address > b->address) - (a->address < b->address);
|
|
|
| + /* Sort locations at the same address by their pspace number, keeping
|
| + locations of the same inferior (in a multi-inferior environment)
|
| + grouped. */
|
| +
|
| + if (a->pspace->num != b->pspace->num)
|
| + return ((a->pspace->num > b->pspace->num)
|
| + - (a->pspace->num < b->pspace->num));
|
| +
|
| /* Sort permanent breakpoints first. */
|
| if (a_perm != b_perm)
|
| return (a_perm < b_perm) - (a_perm > b_perm);
|
|
|
| - /* Make the user-visible order stable across GDB runs. Locations of
|
| - the same breakpoint can be sorted in arbitrary order. */
|
| + /* Make the internal GDB representation stable across GDB runs
|
| + where A and B memory inside GDB can differ. Breakpoint locations of
|
| + the same type at the same address can be sorted in arbitrary order. */
|
|
|
| if (a->owner->number != b->owner->number)
|
| - return (a->owner->number > b->owner->number)
|
| - - (a->owner->number < b->owner->number);
|
| + return ((a->owner->number > b->owner->number)
|
| + - (a->owner->number < b->owner->number));
|
|
|
| return (a > b) - (a < b);
|
| }
|
| @@ -10367,6 +12062,7 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
|
| {
|
| const int left_inserted = left->inserted;
|
| const int left_duplicate = left->duplicate;
|
| + const int left_needs_update = left->needs_update;
|
| const struct bp_target_info left_target_info = left->target_info;
|
|
|
| /* Locations of tracepoints can never be duplicated. */
|
| @@ -10377,12 +12073,67 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
|
|
|
| left->inserted = right->inserted;
|
| left->duplicate = right->duplicate;
|
| + left->needs_update = right->needs_update;
|
| left->target_info = right->target_info;
|
| right->inserted = left_inserted;
|
| right->duplicate = left_duplicate;
|
| + right->needs_update = left_needs_update;
|
| right->target_info = left_target_info;
|
| }
|
|
|
| +/* Force the re-insertion of the locations at ADDRESS. This is called
|
| + once a new/deleted/modified duplicate location is found and we are evaluating
|
| + conditions on the target's side. Such conditions need to be updated on
|
| + the target. */
|
| +
|
| +static void
|
| +force_breakpoint_reinsertion (struct bp_location *bl)
|
| +{
|
| + struct bp_location **locp = NULL, **loc2p;
|
| + struct bp_location *loc;
|
| + CORE_ADDR address = 0;
|
| + int pspace_num;
|
| +
|
| + address = bl->address;
|
| + pspace_num = bl->pspace->num;
|
| +
|
| + /* This is only meaningful if the target is
|
| + evaluating conditions and if the user has
|
| + opted for condition evaluation on the target's
|
| + side. */
|
| + if (gdb_evaluates_breakpoint_condition_p ()
|
| + || !target_supports_evaluation_of_breakpoint_conditions ())
|
| + return;
|
| +
|
| + /* Flag all breakpoint locations with this address and
|
| + the same program space as the location
|
| + as "its condition has changed". We need to
|
| + update the conditions on the target's side. */
|
| + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, address)
|
| + {
|
| + loc = *loc2p;
|
| +
|
| + if (!is_breakpoint (loc->owner)
|
| + || pspace_num != loc->pspace->num)
|
| + continue;
|
| +
|
| + /* Flag the location appropriately. We use a different state to
|
| + let everyone know that we already updated the set of locations
|
| + with addr bl->address and program space bl->pspace. This is so
|
| + we don't have to keep calling these functions just to mark locations
|
| + that have already been marked. */
|
| + loc->condition_changed = condition_updated;
|
| +
|
| + /* Free the agent expression bytecode as well. We will compute
|
| + it later on. */
|
| + if (loc->cond_bytecode)
|
| + {
|
| + free_agent_expr (loc->cond_bytecode);
|
| + loc->cond_bytecode = NULL;
|
| + }
|
| + }
|
| +}
|
| +
|
| /* If SHOULD_INSERT is false, do not insert any breakpoint locations
|
| into the inferior, only remove already-inserted locations that no
|
| longer should be inserted. Functions that delete a breakpoint or
|
| @@ -10404,6 +12155,10 @@ update_global_location_list (int should_insert)
|
| struct breakpoint *b;
|
| struct bp_location **locp, *loc;
|
| struct cleanup *cleanups;
|
| + /* Last breakpoint location address that was marked for update. */
|
| + CORE_ADDR last_addr = 0;
|
| + /* Last breakpoint location program space that was marked for update. */
|
| + int last_pspace_num = -1;
|
|
|
| /* Used in the duplicates detection below. When iterating over all
|
| bp_locations, points to the first bp_location of a given address.
|
| @@ -10476,13 +12231,30 @@ update_global_location_list (int should_insert)
|
| && (*loc2p)->address == old_loc->address);
|
| loc2p++)
|
| {
|
| - if (*loc2p == old_loc)
|
| + /* Check if this is a new/duplicated location or a duplicated
|
| + location that had its condition modified. If so, we want to send
|
| + its condition to the target if evaluation of conditions is taking
|
| + place there. */
|
| + if ((*loc2p)->condition_changed == condition_modified
|
| + && (last_addr != old_loc->address
|
| + || last_pspace_num != old_loc->pspace->num))
|
| {
|
| - found_object = 1;
|
| - break;
|
| + force_breakpoint_reinsertion (*loc2p);
|
| + last_pspace_num = old_loc->pspace->num;
|
| }
|
| +
|
| + if (*loc2p == old_loc)
|
| + found_object = 1;
|
| }
|
|
|
| + /* We have already handled this address, update it so that we don't
|
| + have to go through updates again. */
|
| + last_addr = old_loc->address;
|
| +
|
| + /* Target-side condition evaluation: Handle deleted locations. */
|
| + if (!found_object)
|
| + force_breakpoint_reinsertion (old_loc);
|
| +
|
| /* If this location is no longer present, and inserted, look if
|
| there's maybe a new location at the same address. If so,
|
| mark that one inserted, and don't remove this one. This is
|
| @@ -10502,6 +12274,10 @@ update_global_location_list (int should_insert)
|
| }
|
| else
|
| {
|
| + /* This location still exists, but it won't be kept in the
|
| + target since it may have been disabled. We proceed to
|
| + remove its target-side condition. */
|
| +
|
| /* The location is either no longer present, or got
|
| disabled. See if there's another location at the
|
| same address, in which case we don't need to remove
|
| @@ -10654,7 +12430,11 @@ update_global_location_list (int should_insert)
|
| never duplicated. See the comments in field `duplicate' of
|
| `struct bp_location'. */
|
| || is_tracepoint (b))
|
| - continue;
|
| + {
|
| + /* Clear the condition modification flag. */
|
| + loc->condition_changed = condition_unchanged;
|
| + continue;
|
| + }
|
|
|
| /* Permanent breakpoint should always be inserted. */
|
| if (b->enable_state == bp_permanent && ! loc->inserted)
|
| @@ -10677,6 +12457,13 @@ update_global_location_list (int should_insert)
|
| {
|
| *loc_first_p = loc;
|
| loc->duplicate = 0;
|
| +
|
| + if (is_breakpoint (loc->owner) && loc->condition_changed)
|
| + {
|
| + loc->needs_update = 1;
|
| + /* Clear the condition modification flag. */
|
| + loc->condition_changed = condition_unchanged;
|
| + }
|
| continue;
|
| }
|
|
|
| @@ -10688,6 +12475,9 @@ update_global_location_list (int should_insert)
|
| swap_insertion (loc, *loc_first_p);
|
| loc->duplicate = 1;
|
|
|
| + /* Clear the condition modification flag. */
|
| + loc->condition_changed = condition_unchanged;
|
| +
|
| if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
|
| && b->enable_state != bp_permanent)
|
| internal_error (__FILE__, __LINE__,
|
| @@ -10695,11 +12485,22 @@ update_global_location_list (int should_insert)
|
| "a permanent breakpoint"));
|
| }
|
|
|
| - if (breakpoints_always_inserted_mode () && should_insert
|
| - && (have_live_inferiors ()
|
| - || (gdbarch_has_global_breakpoints (target_gdbarch))))
|
| - insert_breakpoint_locations ();
|
| -
|
| + if (breakpoints_always_inserted_mode ()
|
| + && (have_live_inferiors ()
|
| + || (gdbarch_has_global_breakpoints (target_gdbarch))))
|
| + {
|
| + if (should_insert)
|
| + insert_breakpoint_locations ();
|
| + else
|
| + {
|
| + /* Though should_insert is false, we may need to update conditions
|
| + on the target's side if it is evaluating such conditions. We
|
| + only update conditions for locations that are marked
|
| + "needs_update". */
|
| + update_inserted_breakpoint_locations ();
|
| + }
|
| + }
|
| +
|
| if (should_insert)
|
| download_tracepoint_locations ();
|
|
|
| @@ -10724,7 +12525,7 @@ breakpoint_retire_moribund (void)
|
| static void
|
| update_global_location_list_nothrow (int inserting)
|
| {
|
| - struct gdb_exception e;
|
| + volatile struct gdb_exception e;
|
|
|
| TRY_CATCH (e, RETURN_MASK_ERROR)
|
| update_global_location_list (inserting);
|
| @@ -10812,6 +12613,8 @@ static void
|
| bp_location_dtor (struct bp_location *self)
|
| {
|
| xfree (self->cond);
|
| + if (self->cond_bytecode)
|
| + free_agent_expr (self->cond_bytecode);
|
| xfree (self->function_name);
|
| xfree (self->source_file);
|
| }
|
| @@ -10868,7 +12671,8 @@ base_breakpoint_remove_location (struct bp_location *bl)
|
| static int
|
| base_breakpoint_breakpoint_hit (const struct bp_location *bl,
|
| struct address_space *aspace,
|
| - CORE_ADDR bp_addr)
|
| + CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| internal_error_pure_virtual_called ();
|
| }
|
| @@ -10922,6 +12726,40 @@ base_breakpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
|
| internal_error_pure_virtual_called ();
|
| }
|
|
|
| +static void
|
| +base_breakpoint_create_sals_from_address (char **arg,
|
| + struct linespec_result *canonical,
|
| + enum bptype type_wanted,
|
| + char *addr_start,
|
| + char **copy_arg)
|
| +{
|
| + internal_error_pure_virtual_called ();
|
| +}
|
| +
|
| +static void
|
| +base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch,
|
| + struct linespec_result *c,
|
| + struct linespec_sals *lsal,
|
| + char *cond_string,
|
| + char *extra_string,
|
| + enum bptype type_wanted,
|
| + enum bpdisp disposition,
|
| + int thread,
|
| + int task, int ignore_count,
|
| + const struct breakpoint_ops *o,
|
| + int from_tty, int enabled,
|
| + int internal, unsigned flags)
|
| +{
|
| + internal_error_pure_virtual_called ();
|
| +}
|
| +
|
| +static void
|
| +base_breakpoint_decode_linespec (struct breakpoint *b, char **s,
|
| + struct symtabs_and_lines *sals)
|
| +{
|
| + internal_error_pure_virtual_called ();
|
| +}
|
| +
|
| static struct breakpoint_ops base_breakpoint_ops =
|
| {
|
| base_breakpoint_dtor,
|
| @@ -10937,7 +12775,10 @@ static struct breakpoint_ops base_breakpoint_ops =
|
| NULL,
|
| base_breakpoint_print_one_detail,
|
| base_breakpoint_print_mention,
|
| - base_breakpoint_print_recreate
|
| + base_breakpoint_print_recreate,
|
| + base_breakpoint_create_sals_from_address,
|
| + base_breakpoint_create_breakpoints_sal,
|
| + base_breakpoint_decode_linespec,
|
| };
|
|
|
| /* Default breakpoint_ops methods. */
|
| @@ -10978,10 +12819,15 @@ bkpt_remove_location (struct bp_location *bl)
|
|
|
| static int
|
| bkpt_breakpoint_hit (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct breakpoint *b = bl->owner;
|
|
|
| + if (ws->kind != TARGET_WAITKIND_STOPPED
|
| + || ws->value.sig != GDB_SIGNAL_TRAP)
|
| + return 0;
|
| +
|
| if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
|
| aspace, bp_addr))
|
| return 0;
|
| @@ -11058,6 +12904,9 @@ bkpt_print_mention (struct breakpoint *b)
|
| case bp_hardware_breakpoint:
|
| printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
|
| break;
|
| + case bp_dprintf:
|
| + printf_filtered (_("Dprintf %d"), b->number);
|
| + break;
|
| }
|
|
|
| say_where (b);
|
| @@ -11083,6 +12932,45 @@ bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp)
|
| print_recreate_thread (tp, fp);
|
| }
|
|
|
| +static void
|
| +bkpt_create_sals_from_address (char **arg,
|
| + struct linespec_result *canonical,
|
| + enum bptype type_wanted,
|
| + char *addr_start, char **copy_arg)
|
| +{
|
| + create_sals_from_address_default (arg, canonical, type_wanted,
|
| + addr_start, copy_arg);
|
| +}
|
| +
|
| +static void
|
| +bkpt_create_breakpoints_sal (struct gdbarch *gdbarch,
|
| + struct linespec_result *canonical,
|
| + struct linespec_sals *lsal,
|
| + char *cond_string,
|
| + char *extra_string,
|
| + enum bptype type_wanted,
|
| + enum bpdisp disposition,
|
| + int thread,
|
| + int task, int ignore_count,
|
| + const struct breakpoint_ops *ops,
|
| + int from_tty, int enabled,
|
| + int internal, unsigned flags)
|
| +{
|
| + create_breakpoints_sal_default (gdbarch, canonical, lsal,
|
| + cond_string, extra_string,
|
| + type_wanted,
|
| + disposition, thread, task,
|
| + ignore_count, ops, from_tty,
|
| + enabled, internal, flags);
|
| +}
|
| +
|
| +static void
|
| +bkpt_decode_linespec (struct breakpoint *b, char **s,
|
| + struct symtabs_and_lines *sals)
|
| +{
|
| + decode_linespec_default (b, s, sals);
|
| +}
|
| +
|
| /* Virtual table for internal breakpoints. */
|
|
|
| static void
|
| @@ -11113,8 +13001,17 @@ internal_bkpt_re_set (struct breakpoint *b)
|
| static void
|
| internal_bkpt_check_status (bpstat bs)
|
| {
|
| - /* We do not stop for these. */
|
| - bs->stop = 0;
|
| + if (bs->breakpoint_at->type == bp_shlib_event)
|
| + {
|
| + /* If requested, stop when the dynamic linker notifies GDB of
|
| + events. This allows the user to get control and place
|
| + breakpoints in initializer routines for dynamically loaded
|
| + objects (among other things). */
|
| + bs->stop = stop_on_solib_events;
|
| + bs->print = stop_on_solib_events;
|
| + }
|
| + else
|
| + bs->stop = 0;
|
| }
|
|
|
| static enum print_stop_action
|
| @@ -11131,10 +13028,7 @@ internal_bkpt_print_it (bpstat bs)
|
| /* Did we stop because the user set the stop_on_solib_events
|
| variable? (If so, we report this as a generic, "Stopped due
|
| to shlib event" message.) */
|
| - ui_out_text (uiout, _("Stopped due to shared library event\n"));
|
| - if (ui_out_is_mi_like_p (uiout))
|
| - ui_out_field_string (uiout, "reason",
|
| - async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT));
|
| + print_solib_event (0);
|
| break;
|
|
|
| case bp_thread_event:
|
| @@ -11226,6 +13120,73 @@ momentary_bkpt_print_mention (struct breakpoint *b)
|
| /* Nothing to mention. These breakpoints are internal. */
|
| }
|
|
|
| +/* Ensure INITIATING_FRAME is cleared when no such breakpoint exists.
|
| +
|
| + It gets cleared already on the removal of the first one of such placed
|
| + breakpoints. This is OK as they get all removed altogether. */
|
| +
|
| +static void
|
| +longjmp_bkpt_dtor (struct breakpoint *self)
|
| +{
|
| + struct thread_info *tp = find_thread_id (self->thread);
|
| +
|
| + if (tp)
|
| + tp->initiating_frame = null_frame_id;
|
| +
|
| + momentary_breakpoint_ops.dtor (self);
|
| +}
|
| +
|
| +/* Specific methods for probe breakpoints. */
|
| +
|
| +static int
|
| +bkpt_probe_insert_location (struct bp_location *bl)
|
| +{
|
| + int v = bkpt_insert_location (bl);
|
| +
|
| + if (v == 0)
|
| + {
|
| + /* The insertion was successful, now let's set the probe's semaphore
|
| + if needed. */
|
| + bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch);
|
| + }
|
| +
|
| + return v;
|
| +}
|
| +
|
| +static int
|
| +bkpt_probe_remove_location (struct bp_location *bl)
|
| +{
|
| + /* Let's clear the semaphore before removing the location. */
|
| + bl->probe->pops->clear_semaphore (bl->probe, bl->gdbarch);
|
| +
|
| + return bkpt_remove_location (bl);
|
| +}
|
| +
|
| +static void
|
| +bkpt_probe_create_sals_from_address (char **arg,
|
| + struct linespec_result *canonical,
|
| + enum bptype type_wanted,
|
| + char *addr_start, char **copy_arg)
|
| +{
|
| + struct linespec_sals lsal;
|
| +
|
| + lsal.sals = parse_probes (arg, canonical);
|
| +
|
| + *copy_arg = xstrdup (canonical->addr_string);
|
| + lsal.canonical = xstrdup (*copy_arg);
|
| +
|
| + VEC_safe_push (linespec_sals, canonical->sals, &lsal);
|
| +}
|
| +
|
| +static void
|
| +bkpt_probe_decode_linespec (struct breakpoint *b, char **s,
|
| + struct symtabs_and_lines *sals)
|
| +{
|
| + *sals = parse_probes (s, NULL);
|
| + if (!sals->sals)
|
| + error (_("probe not found"));
|
| +}
|
| +
|
| /* The breakpoint_ops structure to be used in tracepoints. */
|
|
|
| static void
|
| @@ -11236,7 +13197,8 @@ tracepoint_re_set (struct breakpoint *b)
|
|
|
| static int
|
| tracepoint_breakpoint_hit (const struct bp_location *bl,
|
| - struct address_space *aspace, CORE_ADDR bp_addr)
|
| + struct address_space *aspace, CORE_ADDR bp_addr,
|
| + const struct target_waitstatus *ws)
|
| {
|
| /* By definition, the inferior does not report stops at
|
| tracepoints. */
|
| @@ -11309,8 +13271,173 @@ tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
|
| fprintf_unfiltered (fp, " passcount %d\n", tp->pass_count);
|
| }
|
|
|
| +static void
|
| +tracepoint_create_sals_from_address (char **arg,
|
| + struct linespec_result *canonical,
|
| + enum bptype type_wanted,
|
| + char *addr_start, char **copy_arg)
|
| +{
|
| + create_sals_from_address_default (arg, canonical, type_wanted,
|
| + addr_start, copy_arg);
|
| +}
|
| +
|
| +static void
|
| +tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch,
|
| + struct linespec_result *canonical,
|
| + struct linespec_sals *lsal,
|
| + char *cond_string,
|
| + char *extra_string,
|
| + enum bptype type_wanted,
|
| + enum bpdisp disposition,
|
| + int thread,
|
| + int task, int ignore_count,
|
| + const struct breakpoint_ops *ops,
|
| + int from_tty, int enabled,
|
| + int internal, unsigned flags)
|
| +{
|
| + create_breakpoints_sal_default (gdbarch, canonical, lsal,
|
| + cond_string, extra_string,
|
| + type_wanted,
|
| + disposition, thread, task,
|
| + ignore_count, ops, from_tty,
|
| + enabled, internal, flags);
|
| +}
|
| +
|
| +static void
|
| +tracepoint_decode_linespec (struct breakpoint *b, char **s,
|
| + struct symtabs_and_lines *sals)
|
| +{
|
| + decode_linespec_default (b, s, sals);
|
| +}
|
| +
|
| struct breakpoint_ops tracepoint_breakpoint_ops;
|
|
|
| +/* The breakpoint_ops structure to be use on tracepoints placed in a
|
| + static probe. */
|
| +
|
| +static void
|
| +tracepoint_probe_create_sals_from_address (char **arg,
|
| + struct linespec_result *canonical,
|
| + enum bptype type_wanted,
|
| + char *addr_start, char **copy_arg)
|
| +{
|
| + /* We use the same method for breakpoint on probes. */
|
| + bkpt_probe_create_sals_from_address (arg, canonical, type_wanted,
|
| + addr_start, copy_arg);
|
| +}
|
| +
|
| +static void
|
| +tracepoint_probe_decode_linespec (struct breakpoint *b, char **s,
|
| + struct symtabs_and_lines *sals)
|
| +{
|
| + /* We use the same method for breakpoint on probes. */
|
| + bkpt_probe_decode_linespec (b, s, sals);
|
| +}
|
| +
|
| +static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
|
| +
|
| +/* The breakpoint_ops structure to be used on static tracepoints with
|
| + markers (`-m'). */
|
| +
|
| +static void
|
| +strace_marker_create_sals_from_address (char **arg,
|
| + struct linespec_result *canonical,
|
| + enum bptype type_wanted,
|
| + char *addr_start, char **copy_arg)
|
| +{
|
| + struct linespec_sals lsal;
|
| +
|
| + lsal.sals = decode_static_tracepoint_spec (arg);
|
| +
|
| + *copy_arg = savestring (addr_start, *arg - addr_start);
|
| +
|
| + canonical->addr_string = xstrdup (*copy_arg);
|
| + lsal.canonical = xstrdup (*copy_arg);
|
| + VEC_safe_push (linespec_sals, canonical->sals, &lsal);
|
| +}
|
| +
|
| +static void
|
| +strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
|
| + struct linespec_result *canonical,
|
| + struct linespec_sals *lsal,
|
| + char *cond_string,
|
| + char *extra_string,
|
| + enum bptype type_wanted,
|
| + enum bpdisp disposition,
|
| + int thread,
|
| + int task, int ignore_count,
|
| + const struct breakpoint_ops *ops,
|
| + int from_tty, int enabled,
|
| + int internal, unsigned flags)
|
| +{
|
| + int i;
|
| +
|
| + /* If the user is creating a static tracepoint by marker id
|
| + (strace -m MARKER_ID), then store the sals index, so that
|
| + breakpoint_re_set can try to match up which of the newly
|
| + found markers corresponds to this one, and, don't try to
|
| + expand multiple locations for each sal, given than SALS
|
| + already should contain all sals for MARKER_ID. */
|
| +
|
| + for (i = 0; i < lsal->sals.nelts; ++i)
|
| + {
|
| + struct symtabs_and_lines expanded;
|
| + struct tracepoint *tp;
|
| + struct cleanup *old_chain;
|
| + char *addr_string;
|
| +
|
| + expanded.nelts = 1;
|
| + expanded.sals = &lsal->sals.sals[i];
|
| +
|
| + addr_string = xstrdup (canonical->addr_string);
|
| + old_chain = make_cleanup (xfree, addr_string);
|
| +
|
| + tp = XCNEW (struct tracepoint);
|
| + init_breakpoint_sal (&tp->base, gdbarch, expanded,
|
| + addr_string, NULL,
|
| + cond_string, extra_string,
|
| + type_wanted, disposition,
|
| + thread, task, ignore_count, ops,
|
| + from_tty, enabled, internal, flags,
|
| + canonical->special_display);
|
| + /* Given that its possible to have multiple markers with
|
| + the same string id, if the user is creating a static
|
| + tracepoint by marker id ("strace -m MARKER_ID"), then
|
| + store the sals index, so that breakpoint_re_set can
|
| + try to match up which of the newly found markers
|
| + corresponds to this one */
|
| + tp->static_trace_marker_id_idx = i;
|
| +
|
| + install_breakpoint (internal, &tp->base, 0);
|
| +
|
| + discard_cleanups (old_chain);
|
| + }
|
| +}
|
| +
|
| +static void
|
| +strace_marker_decode_linespec (struct breakpoint *b, char **s,
|
| + struct symtabs_and_lines *sals)
|
| +{
|
| + struct tracepoint *tp = (struct tracepoint *) b;
|
| +
|
| + *sals = decode_static_tracepoint_spec (s);
|
| + if (sals->nelts > tp->static_trace_marker_id_idx)
|
| + {
|
| + sals->sals[0] = sals->sals[tp->static_trace_marker_id_idx];
|
| + sals->nelts = 1;
|
| + }
|
| + else
|
| + error (_("marker %s not found"), tp->static_trace_marker_id);
|
| +}
|
| +
|
| +static struct breakpoint_ops strace_marker_breakpoint_ops;
|
| +
|
| +static int
|
| +strace_marker_p (struct breakpoint *b)
|
| +{
|
| + return b->ops == &strace_marker_breakpoint_ops;
|
| +}
|
| +
|
| /* Delete a breakpoint and clean up all traces of it in the data
|
| structures. */
|
|
|
| @@ -11592,7 +13719,6 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
|
| struct tracepoint *tp = (struct tracepoint *) b;
|
| struct static_tracepoint_marker marker;
|
| CORE_ADDR pc;
|
| - int i;
|
|
|
| pc = sal.pc;
|
| if (sal.line)
|
| @@ -11764,12 +13890,13 @@ update_breakpoint_locations (struct breakpoint *b,
|
| if (b->cond_string != NULL)
|
| {
|
| char *s;
|
| - struct gdb_exception e;
|
| + volatile struct gdb_exception e;
|
|
|
| s = b->cond_string;
|
| TRY_CATCH (e, RETURN_MASK_ERROR)
|
| {
|
| - new_loc->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc),
|
| + new_loc->cond = parse_exp_1 (&s, sals.sals[i].pc,
|
| + block_for_pc (sals.sals[i].pc),
|
| 0);
|
| }
|
| if (e.reason < 0)
|
| @@ -11845,54 +13972,15 @@ static struct symtabs_and_lines
|
| addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
|
| {
|
| char *s;
|
| - int marker_spec;
|
| struct symtabs_and_lines sals = {0};
|
| volatile struct gdb_exception e;
|
|
|
| + gdb_assert (b->ops != NULL);
|
| s = addr_string;
|
| - marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
|
|
|
| TRY_CATCH (e, RETURN_MASK_ERROR)
|
| {
|
| - if (marker_spec)
|
| - {
|
| - struct tracepoint *tp = (struct tracepoint *) b;
|
| -
|
| - sals = decode_static_tracepoint_spec (&s);
|
| - if (sals.nelts > tp->static_trace_marker_id_idx)
|
| - {
|
| - sals.sals[0] = sals.sals[tp->static_trace_marker_id_idx];
|
| - sals.nelts = 1;
|
| - }
|
| - else
|
| - error (_("marker %s not found"), tp->static_trace_marker_id);
|
| - }
|
| - else
|
| - {
|
| - struct linespec_result canonical;
|
| -
|
| - init_linespec_result (&canonical);
|
| - decode_line_full (&s, DECODE_LINE_FUNFIRSTLINE,
|
| - (struct symtab *) NULL, 0,
|
| - &canonical, multiple_symbols_all,
|
| - b->filter);
|
| -
|
| - /* We should get 0 or 1 resulting SALs. */
|
| - gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
|
| -
|
| - if (VEC_length (linespec_sals, canonical.sals) > 0)
|
| - {
|
| - struct linespec_sals *lsal;
|
| -
|
| - lsal = VEC_index (linespec_sals, canonical.sals, 0);
|
| - sals = lsal->sals;
|
| - /* Arrange it so the destructor does not free the
|
| - contents. */
|
| - lsal->sals.sals = NULL;
|
| - }
|
| -
|
| - destroy_linespec_result (&canonical);
|
| - }
|
| + b->ops->decode_linespec (b, &s, &sals);
|
| }
|
| if (e.reason < 0)
|
| {
|
| @@ -11935,17 +14023,21 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
|
| char *cond_string = 0;
|
| int thread = -1;
|
| int task = 0;
|
| + char *extra_string = NULL;
|
|
|
| find_condition_and_thread (s, sals.sals[0].pc,
|
| - &cond_string, &thread, &task);
|
| + &cond_string, &thread, &task,
|
| + &extra_string);
|
| if (cond_string)
|
| b->cond_string = cond_string;
|
| b->thread = thread;
|
| b->task = task;
|
| + if (extra_string)
|
| + b->extra_string = extra_string;
|
| b->condition_not_parsed = 0;
|
| }
|
|
|
| - if (b->type == bp_static_tracepoint && !marker_spec)
|
| + if (b->type == bp_static_tracepoint && !strace_marker_p (b))
|
| sals.sals[0] = update_static_tracepoint (b, sals.sals[0]);
|
|
|
| *found = 1;
|
| @@ -11988,6 +14080,75 @@ breakpoint_re_set_default (struct breakpoint *b)
|
| update_breakpoint_locations (b, expanded, expanded_end);
|
| }
|
|
|
| +/* Default method for creating SALs from an address string. It basically
|
| + calls parse_breakpoint_sals. Return 1 for success, zero for failure. */
|
| +
|
| +static void
|
| +create_sals_from_address_default (char **arg,
|
| + struct linespec_result *canonical,
|
| + enum bptype type_wanted,
|
| + char *addr_start, char **copy_arg)
|
| +{
|
| + parse_breakpoint_sals (arg, canonical);
|
| +}
|
| +
|
| +/* Call create_breakpoints_sal for the given arguments. This is the default
|
| + function for the `create_breakpoints_sal' method of
|
| + breakpoint_ops. */
|
| +
|
| +static void
|
| +create_breakpoints_sal_default (struct gdbarch *gdbarch,
|
| + struct linespec_result *canonical,
|
| + struct linespec_sals *lsal,
|
| + char *cond_string,
|
| + char *extra_string,
|
| + enum bptype type_wanted,
|
| + enum bpdisp disposition,
|
| + int thread,
|
| + int task, int ignore_count,
|
| + const struct breakpoint_ops *ops,
|
| + int from_tty, int enabled,
|
| + int internal, unsigned flags)
|
| +{
|
| + create_breakpoints_sal (gdbarch, canonical, cond_string,
|
| + extra_string,
|
| + type_wanted, disposition,
|
| + thread, task, ignore_count, ops, from_tty,
|
| + enabled, internal, flags);
|
| +}
|
| +
|
| +/* Decode the line represented by S by calling decode_line_full. This is the
|
| + default function for the `decode_linespec' method of breakpoint_ops. */
|
| +
|
| +static void
|
| +decode_linespec_default (struct breakpoint *b, char **s,
|
| + struct symtabs_and_lines *sals)
|
| +{
|
| + struct linespec_result canonical;
|
| +
|
| + init_linespec_result (&canonical);
|
| + decode_line_full (s, DECODE_LINE_FUNFIRSTLINE,
|
| + (struct symtab *) NULL, 0,
|
| + &canonical, multiple_symbols_all,
|
| + b->filter);
|
| +
|
| + /* We should get 0 or 1 resulting SALs. */
|
| + gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
|
| +
|
| + if (VEC_length (linespec_sals, canonical.sals) > 0)
|
| + {
|
| + struct linespec_sals *lsal;
|
| +
|
| + lsal = VEC_index (linespec_sals, canonical.sals, 0);
|
| + *sals = lsal->sals;
|
| + /* Arrange it so the destructor does not free the
|
| + contents. */
|
| + lsal->sals.sals = NULL;
|
| + }
|
| +
|
| + destroy_linespec_result (&canonical);
|
| +}
|
| +
|
| /* Prepare the global context for a re-set of breakpoint B. */
|
|
|
| static struct cleanup *
|
| @@ -12254,6 +14415,9 @@ disable_breakpoint (struct breakpoint *bpt)
|
|
|
| bpt->enable_state = bp_disabled;
|
|
|
| + /* Mark breakpoint locations modified. */
|
| + mark_breakpoint_modified (bpt);
|
| +
|
| if (target_supports_enable_disable_tracepoint ()
|
| && current_trace_status ()->running && is_tracepoint (bpt))
|
| {
|
| @@ -12301,7 +14465,11 @@ disable_command (char *args, int from_tty)
|
| struct bp_location *loc = find_location_by_number (args);
|
| if (loc)
|
| {
|
| - loc->enabled = 0;
|
| + if (loc->enabled)
|
| + {
|
| + loc->enabled = 0;
|
| + mark_breakpoint_location_modified (loc);
|
| + }
|
| if (target_supports_enable_disable_tracepoint ()
|
| && current_trace_status ()->running && loc->owner
|
| && is_tracepoint (loc->owner))
|
| @@ -12314,7 +14482,8 @@ disable_command (char *args, int from_tty)
|
| }
|
|
|
| static void
|
| -enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
|
| +enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition,
|
| + int count)
|
| {
|
| int target_resources_ok;
|
|
|
| @@ -12335,7 +14504,7 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
|
| {
|
| /* Initialize it just to avoid a GCC false warning. */
|
| enum enable_state orig_enable_state = 0;
|
| - struct gdb_exception e;
|
| + volatile struct gdb_exception e;
|
|
|
| TRY_CATCH (e, RETURN_MASK_ALL)
|
| {
|
| @@ -12357,6 +14526,11 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
|
| if (bpt->enable_state != bp_permanent)
|
| bpt->enable_state = bp_enabled;
|
|
|
| + bpt->enable_state = bp_enabled;
|
| +
|
| + /* Mark breakpoint locations modified. */
|
| + mark_breakpoint_modified (bpt);
|
| +
|
| if (target_supports_enable_disable_tracepoint ()
|
| && current_trace_status ()->running && is_tracepoint (bpt))
|
| {
|
| @@ -12367,6 +14541,7 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
|
| }
|
|
|
| bpt->disposition = disposition;
|
| + bpt->enable_count = count;
|
| update_global_location_list (1);
|
| breakpoints_changed ();
|
|
|
| @@ -12377,7 +14552,7 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
|
| void
|
| enable_breakpoint (struct breakpoint *bpt)
|
| {
|
| - enable_breakpoint_disp (bpt, bpt->disposition);
|
| + enable_breakpoint_disp (bpt, bpt->disposition, 0);
|
| }
|
|
|
| static void
|
| @@ -12415,7 +14590,11 @@ enable_command (char *args, int from_tty)
|
| struct bp_location *loc = find_location_by_number (args);
|
| if (loc)
|
| {
|
| - loc->enabled = 1;
|
| + if (!loc->enabled)
|
| + {
|
| + loc->enabled = 1;
|
| + mark_breakpoint_location_modified (loc);
|
| + }
|
| if (target_supports_enable_disable_tracepoint ()
|
| && current_trace_status ()->running && loc->owner
|
| && is_tracepoint (loc->owner))
|
| @@ -12427,18 +14606,27 @@ enable_command (char *args, int from_tty)
|
| map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
|
| }
|
|
|
| +/* This struct packages up disposition data for application to multiple
|
| + breakpoints. */
|
| +
|
| +struct disp_data
|
| +{
|
| + enum bpdisp disp;
|
| + int count;
|
| +};
|
| +
|
| static void
|
| do_enable_breakpoint_disp (struct breakpoint *bpt, void *arg)
|
| {
|
| - enum bpdisp disp = *(enum bpdisp *) arg;
|
| + struct disp_data disp_data = *(struct disp_data *) arg;
|
|
|
| - enable_breakpoint_disp (bpt, disp);
|
| + enable_breakpoint_disp (bpt, disp_data.disp, disp_data.count);
|
| }
|
|
|
| static void
|
| do_map_enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
|
| {
|
| - enum bpdisp disp = disp_disable;
|
| + struct disp_data disp = { disp_disable, 1 };
|
|
|
| iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
|
| }
|
| @@ -12450,9 +14638,25 @@ enable_once_command (char *args, int from_tty)
|
| }
|
|
|
| static void
|
| +do_map_enable_count_breakpoint (struct breakpoint *bpt, void *countptr)
|
| +{
|
| + struct disp_data disp = { disp_disable, *(int *) countptr };
|
| +
|
| + iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
|
| +}
|
| +
|
| +static void
|
| +enable_count_command (char *args, int from_tty)
|
| +{
|
| + int count = get_number (&args);
|
| +
|
| + map_breakpoint_numbers (args, do_map_enable_count_breakpoint, &count);
|
| +}
|
| +
|
| +static void
|
| do_map_enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
|
| {
|
| - enum bpdisp disp = disp_del;
|
| + struct disp_data disp = { disp_del, 1 };
|
|
|
| iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
|
| }
|
| @@ -12506,27 +14710,6 @@ invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
|
| }
|
| }
|
|
|
| -/* Use the last displayed codepoint's values, or nothing
|
| - if they aren't valid. */
|
| -
|
| -struct symtabs_and_lines
|
| -decode_line_spec_1 (char *string, int flags)
|
| -{
|
| - struct symtabs_and_lines sals;
|
| -
|
| - if (string == 0)
|
| - error (_("Empty line specification."));
|
| - if (last_displayed_sal_is_valid ())
|
| - sals = decode_line_1 (&string, flags,
|
| - get_last_displayed_symtab (),
|
| - get_last_displayed_line ());
|
| - else
|
| - sals = decode_line_1 (&string, flags, (struct symtab *) NULL, 0);
|
| - if (*string)
|
| - error (_("Junk at end of line specification: %s"), string);
|
| - return sals;
|
| -}
|
| -
|
| /* Create and insert a raw software breakpoint at PC. Return an
|
| identifier, which should be used to remove the breakpoint later.
|
| In general, places which call this should be using something on the
|
| @@ -12713,9 +14896,10 @@ is_syscall_catchpoint_enabled (struct breakpoint *bp)
|
| int
|
| catch_syscall_enabled (void)
|
| {
|
| - struct inferior *inf = current_inferior ();
|
| + struct catch_syscall_inferior_data *inf_data
|
| + = get_catch_syscall_inferior_data (current_inferior ());
|
|
|
| - return inf->total_syscalls_count != 0;
|
| + return inf_data->total_syscalls_count != 0;
|
| }
|
|
|
| int
|
| @@ -12745,12 +14929,12 @@ catching_syscall_number (int syscall_number)
|
| }
|
|
|
| /* Complete syscall names. Used by "catch syscall". */
|
| -static char **
|
| +static VEC (char_ptr) *
|
| catch_syscall_completer (struct cmd_list_element *cmd,
|
| char *text, char *word)
|
| {
|
| const char **list = get_syscall_names ();
|
| - char **retlist
|
| + VEC (char_ptr) *retlist
|
| = (list == NULL) ? NULL : complete_on_enum (list, text, word);
|
|
|
| xfree (list);
|
| @@ -12767,29 +14951,37 @@ set_tracepoint_count (int num)
|
| set_internalvar_integer (lookup_internalvar ("tpnum"), num);
|
| }
|
|
|
| -void
|
| +static void
|
| trace_command (char *arg, int from_tty)
|
| {
|
| + struct breakpoint_ops *ops;
|
| + const char *arg_cp = arg;
|
| +
|
| + if (arg && probe_linespec_to_ops (&arg_cp))
|
| + ops = &tracepoint_probe_breakpoint_ops;
|
| + else
|
| + ops = &tracepoint_breakpoint_ops;
|
| +
|
| if (create_breakpoint (get_current_arch (),
|
| arg,
|
| - NULL, 0, 1 /* parse arg */,
|
| + NULL, 0, NULL, 1 /* parse arg */,
|
| 0 /* tempflag */,
|
| bp_tracepoint /* type_wanted */,
|
| 0 /* Ignore count */,
|
| pending_break_support,
|
| - &tracepoint_breakpoint_ops,
|
| + ops,
|
| from_tty,
|
| 1 /* enabled */,
|
| 0 /* internal */, 0))
|
| set_tracepoint_count (breakpoint_count);
|
| }
|
|
|
| -void
|
| +static void
|
| ftrace_command (char *arg, int from_tty)
|
| {
|
| if (create_breakpoint (get_current_arch (),
|
| arg,
|
| - NULL, 0, 1 /* parse arg */,
|
| + NULL, 0, NULL, 1 /* parse arg */,
|
| 0 /* tempflag */,
|
| bp_fast_tracepoint /* type_wanted */,
|
| 0 /* Ignore count */,
|
| @@ -12803,17 +14995,26 @@ ftrace_command (char *arg, int from_tty)
|
|
|
| /* strace command implementation. Creates a static tracepoint. */
|
|
|
| -void
|
| +static void
|
| strace_command (char *arg, int from_tty)
|
| {
|
| + struct breakpoint_ops *ops;
|
| +
|
| + /* Decide if we are dealing with a static tracepoint marker (`-m'),
|
| + or with a normal static tracepoint. */
|
| + if (arg && strncmp (arg, "-m", 2) == 0 && isspace (arg[2]))
|
| + ops = &strace_marker_breakpoint_ops;
|
| + else
|
| + ops = &tracepoint_breakpoint_ops;
|
| +
|
| if (create_breakpoint (get_current_arch (),
|
| arg,
|
| - NULL, 0, 1 /* parse arg */,
|
| + NULL, 0, NULL, 1 /* parse arg */,
|
| 0 /* tempflag */,
|
| bp_static_tracepoint /* type_wanted */,
|
| 0 /* Ignore count */,
|
| pending_break_support,
|
| - &tracepoint_breakpoint_ops,
|
| + ops,
|
| from_tty,
|
| 1 /* enabled */,
|
| 0 /* internal */, 0))
|
| @@ -12873,7 +15074,8 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
|
|
|
| if (!create_breakpoint (get_current_arch (),
|
| addr_str,
|
| - utp->cond_string, -1, 0 /* parse cond/thread */,
|
| + utp->cond_string, -1, NULL,
|
| + 0 /* parse cond/thread */,
|
| 0 /* tempflag */,
|
| utp->type /* type_wanted */,
|
| 0 /* Ignore count */,
|
| @@ -13323,7 +15525,10 @@ all_tracepoints (void)
|
| COMMAND should be a string constant containing the name of the
|
| command. */
|
| #define BREAK_ARGS_HELP(command) \
|
| -command" [LOCATION] [thread THREADNUM] [if CONDITION]\n\
|
| +command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
|
| +PROBE_MODIFIER shall be present if the command is to be placed in a\n\
|
| +probe point. Accepted values are `-probe' (for a generic, automatically\n\
|
| +guessed probe type) or `-probe-stap' (for a SystemTap probe).\n\
|
| LOCATION may be a line number, function name, or \"*\" and an address.\n\
|
| If a line number is specified, break at start of code for that line.\n\
|
| If a function is specified, break at start of code for that function.\n\
|
| @@ -13349,8 +15554,7 @@ void
|
| add_catch_command (char *name, char *docstring,
|
| void (*sfunc) (char *args, int from_tty,
|
| struct cmd_list_element *command),
|
| - char **(*completer) (struct cmd_list_element *cmd,
|
| - char *text, char *word),
|
| + completer_ftype *completer,
|
| void *user_data_catch,
|
| void *user_data_tcatch)
|
| {
|
| @@ -13372,9 +15576,12 @@ add_catch_command (char *name, char *docstring,
|
| static void
|
| clear_syscall_counts (struct inferior *inf)
|
| {
|
| - inf->total_syscalls_count = 0;
|
| - inf->any_syscall_count = 0;
|
| - VEC_free (int, inf->syscalls_counts);
|
| + struct catch_syscall_inferior_data *inf_data
|
| + = get_catch_syscall_inferior_data (inf);
|
| +
|
| + inf_data->total_syscalls_count = 0;
|
| + inf_data->any_syscall_count = 0;
|
| + VEC_free (int, inf_data->syscalls_counts);
|
| }
|
|
|
| static void
|
| @@ -13418,7 +15625,8 @@ is_non_inline_function (struct breakpoint *b)
|
| have been inlined. */
|
|
|
| int
|
| -pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc)
|
| +pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc,
|
| + const struct target_waitstatus *ws)
|
| {
|
| struct breakpoint *b;
|
| struct bp_location *bl;
|
| @@ -13431,7 +15639,7 @@ pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc)
|
| for (bl = b->loc; bl != NULL; bl = bl->next)
|
| {
|
| if (!bl->shlib_disabled
|
| - && bpstat_check_location (bl, aspace, pc))
|
| + && bpstat_check_location (bl, aspace, pc, ws))
|
| return 1;
|
| }
|
| }
|
| @@ -13459,6 +15667,9 @@ initialize_breakpoint_ops (void)
|
| ops->insert_location = bkpt_insert_location;
|
| ops->remove_location = bkpt_remove_location;
|
| ops->breakpoint_hit = bkpt_breakpoint_hit;
|
| + ops->create_sals_from_address = bkpt_create_sals_from_address;
|
| + ops->create_breakpoints_sal = bkpt_create_breakpoints_sal;
|
| + ops->decode_linespec = bkpt_decode_linespec;
|
|
|
| /* The breakpoint_ops structure to be used in regular breakpoints. */
|
| ops = &bkpt_breakpoint_ops;
|
| @@ -13496,6 +15707,19 @@ initialize_breakpoint_ops (void)
|
| ops->print_it = momentary_bkpt_print_it;
|
| ops->print_mention = momentary_bkpt_print_mention;
|
|
|
| + /* Momentary breakpoints for bp_longjmp and bp_exception. */
|
| + ops = &longjmp_breakpoint_ops;
|
| + *ops = momentary_breakpoint_ops;
|
| + ops->dtor = longjmp_bkpt_dtor;
|
| +
|
| + /* Probe breakpoints. */
|
| + ops = &bkpt_probe_breakpoint_ops;
|
| + *ops = bkpt_breakpoint_ops;
|
| + ops->insert_location = bkpt_probe_insert_location;
|
| + ops->remove_location = bkpt_probe_remove_location;
|
| + ops->create_sals_from_address = bkpt_probe_create_sals_from_address;
|
| + ops->decode_linespec = bkpt_probe_decode_linespec;
|
| +
|
| /* GNU v3 exception catchpoints. */
|
| ops = &gnu_v3_exception_catchpoint_ops;
|
| *ops = bkpt_breakpoint_ops;
|
| @@ -13539,6 +15763,22 @@ initialize_breakpoint_ops (void)
|
| ops->print_one_detail = tracepoint_print_one_detail;
|
| ops->print_mention = tracepoint_print_mention;
|
| ops->print_recreate = tracepoint_print_recreate;
|
| + ops->create_sals_from_address = tracepoint_create_sals_from_address;
|
| + ops->create_breakpoints_sal = tracepoint_create_breakpoints_sal;
|
| + ops->decode_linespec = tracepoint_decode_linespec;
|
| +
|
| + /* Probe tracepoints. */
|
| + ops = &tracepoint_probe_breakpoint_ops;
|
| + *ops = tracepoint_breakpoint_ops;
|
| + ops->create_sals_from_address = tracepoint_probe_create_sals_from_address;
|
| + ops->decode_linespec = tracepoint_probe_decode_linespec;
|
| +
|
| + /* Static tracepoints with marker (`-m'). */
|
| + ops = &strace_marker_breakpoint_ops;
|
| + *ops = tracepoint_breakpoint_ops;
|
| + ops->create_sals_from_address = strace_marker_create_sals_from_address;
|
| + ops->create_breakpoints_sal = strace_marker_create_breakpoints_sal;
|
| + ops->decode_linespec = strace_marker_decode_linespec;
|
|
|
| /* Fork catchpoints. */
|
| ops = &catch_fork_breakpoint_ops;
|
| @@ -13585,6 +15825,27 @@ initialize_breakpoint_ops (void)
|
| ops->print_one = print_one_catch_syscall;
|
| ops->print_mention = print_mention_catch_syscall;
|
| ops->print_recreate = print_recreate_catch_syscall;
|
| +
|
| + /* Solib-related catchpoints. */
|
| + ops = &catch_solib_breakpoint_ops;
|
| + *ops = base_breakpoint_ops;
|
| + ops->dtor = dtor_catch_solib;
|
| + ops->insert_location = insert_catch_solib;
|
| + ops->remove_location = remove_catch_solib;
|
| + ops->breakpoint_hit = breakpoint_hit_catch_solib;
|
| + ops->check_status = check_status_catch_solib;
|
| + ops->print_it = print_it_catch_solib;
|
| + ops->print_one = print_one_catch_solib;
|
| + ops->print_mention = print_mention_catch_solib;
|
| + ops->print_recreate = print_recreate_catch_solib;
|
| +
|
| + ops = &dprintf_breakpoint_ops;
|
| + *ops = bkpt_base_breakpoint_ops;
|
| + ops->re_set = bkpt_re_set;
|
| + ops->resources_needed = bkpt_resources_needed;
|
| + ops->print_it = bkpt_print_it;
|
| + ops->print_mention = bkpt_print_mention;
|
| + ops->print_recreate = bkpt_print_recreate;
|
| }
|
|
|
| void
|
| @@ -13598,7 +15859,11 @@ _initialize_breakpoint (void)
|
| observer_attach_inferior_exit (clear_syscall_counts);
|
| observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
|
|
|
| - breakpoint_objfile_key = register_objfile_data ();
|
| + breakpoint_objfile_key
|
| + = register_objfile_data_with_cleanup (NULL, free_breakpoint_probes);
|
| +
|
| + catch_syscall_inferior_data
|
| + = register_inferior_data_with_cleanup (catch_syscall_inferior_data_cleanup);
|
|
|
| breakpoint_chain = 0;
|
| /* Don't bother to call set_breakpoint_count. $bpnum isn't useful
|
| @@ -13622,10 +15887,11 @@ Type a line containing \"end\" to indicate the end of them.\n\
|
| Give \"silent\" as the first line to make the breakpoint silent;\n\
|
| then no output is printed when it is hit, except what the commands print."));
|
|
|
| - add_com ("condition", class_breakpoint, condition_command, _("\
|
| + c = add_com ("condition", class_breakpoint, condition_command, _("\
|
| Specify breakpoint number N to break only if COND is true.\n\
|
| Usage is `condition N COND', where N is an integer and COND is an\n\
|
| expression to be evaluated whenever breakpoint N is reached."));
|
| + set_cmd_completer (c, condition_completer);
|
|
|
| c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\
|
| Set a temporary breakpoint.\n\
|
| @@ -13686,6 +15952,12 @@ Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
|
| If a breakpoint is hit while enabled in this fashion, it is deleted."),
|
| &enablebreaklist);
|
|
|
| + add_cmd ("count", no_class, enable_count_command, _("\
|
| +Enable breakpoints for COUNT hits. Give count and then breakpoint numbers.\n\
|
| +If a breakpoint is hit while enabled in this fashion,\n\
|
| +the count is decremented; when it reaches zero, the breakpoint is disabled."),
|
| + &enablebreaklist);
|
| +
|
| add_cmd ("delete", no_class, enable_delete_command, _("\
|
| Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
|
| If a breakpoint is hit while enabled in this fashion, it is deleted."),
|
| @@ -13696,6 +15968,12 @@ Enable breakpoints for one hit. Give breakpoint numbers.\n\
|
| If a breakpoint is hit while enabled in this fashion, it becomes disabled."),
|
| &enablelist);
|
|
|
| + add_cmd ("count", no_class, enable_count_command, _("\
|
| +Enable breakpoints for COUNT hits. Give count and then breakpoint numbers.\n\
|
| +If a breakpoint is hit while enabled in this fashion,\n\
|
| +the count is decremented; when it reaches zero, the breakpoint is disabled."),
|
| + &enablelist);
|
| +
|
| add_prefix_cmd ("disable", class_breakpoint, disable_command, _("\
|
| Disable some breakpoints.\n\
|
| Arguments are breakpoint numbers with spaces in between.\n\
|
| @@ -13862,15 +16140,13 @@ Set temporary catchpoints to catch events."),
|
|
|
| /* Add catch and tcatch sub-commands. */
|
| add_catch_command ("catch", _("\
|
| -Catch an exception, when caught.\n\
|
| -With an argument, catch only exceptions with the given name."),
|
| +Catch an exception, when caught."),
|
| catch_catch_command,
|
| NULL,
|
| CATCH_PERMANENT,
|
| CATCH_TEMPORARY);
|
| add_catch_command ("throw", _("\
|
| -Catch an exception, when thrown.\n\
|
| -With an argument, catch only exceptions with the given name."),
|
| +Catch an exception, when thrown."),
|
| catch_throw_command,
|
| NULL,
|
| CATCH_PERMANENT,
|
| @@ -13890,6 +16166,20 @@ With an argument, catch only exceptions with the given name."),
|
| NULL,
|
| CATCH_PERMANENT,
|
| CATCH_TEMPORARY);
|
| + add_catch_command ("load", _("Catch loads of shared libraries.\n\
|
| +Usage: catch load [REGEX]\n\
|
| +If REGEX is given, only stop for libraries matching the regular expression."),
|
| + catch_load_command_1,
|
| + NULL,
|
| + CATCH_PERMANENT,
|
| + CATCH_TEMPORARY);
|
| + add_catch_command ("unload", _("Catch unloads of shared libraries.\n\
|
| +Usage: catch unload [REGEX]\n\
|
| +If REGEX is given, only stop for libraries matching the regular expression."),
|
| + catch_unload_command_1,
|
| + NULL,
|
| + CATCH_PERMANENT,
|
| + CATCH_TEMPORARY);
|
| add_catch_command ("syscall", _("\
|
| Catch system calls by their names and/or numbers.\n\
|
| Arguments say which system calls to catch. If no arguments\n\
|
| @@ -14089,8 +16379,8 @@ a warning will be emitted for such breakpoints."),
|
| &breakpoint_set_cmdlist,
|
| &breakpoint_show_cmdlist);
|
|
|
| - add_setshow_enum_cmd ("always-inserted", class_support,
|
| - always_inserted_enums, &always_inserted_mode, _("\
|
| + add_setshow_auto_boolean_cmd ("always-inserted", class_support,
|
| + &always_inserted_mode, _("\
|
| Set mode for inserting breakpoints."), _("\
|
| Show mode for inserting breakpoints."), _("\
|
| When this mode is off, breakpoints are inserted in inferior when it is\n\
|
| @@ -14101,8 +16391,25 @@ the behaviour depends on the non-stop setting (see help set non-stop).\n\
|
| In this case, if gdb is controlling the inferior in non-stop mode, gdb\n\
|
| behaves as if always-inserted mode is on; if gdb is controlling the\n\
|
| inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
|
| - NULL,
|
| - &show_always_inserted_mode,
|
| + NULL,
|
| + &show_always_inserted_mode,
|
| + &breakpoint_set_cmdlist,
|
| + &breakpoint_show_cmdlist);
|
| +
|
| + add_setshow_enum_cmd ("condition-evaluation", class_breakpoint,
|
| + condition_evaluation_enums,
|
| + &condition_evaluation_mode_1, _("\
|
| +Set mode of breakpoint condition evaluation."), _("\
|
| +Show mode of breakpoint condition evaluation."), _("\
|
| +When this is set to \"host\", breakpoint conditions will be\n\
|
| +evaluated on the host's side by GDB. When it is set to \"target\",\n\
|
| +breakpoint conditions will be downloaded to the target (if the target\n\
|
| +supports such feature) and conditions will be evaluated on the target's side.\n\
|
| +If this is set to \"auto\" (default), this will be automatically set to\n\
|
| +\"target\" if it supports condition evaluation, otherwise it will\n\
|
| +be set to \"gdb\""),
|
| + &set_condition_evaluation_mode,
|
| + &show_condition_evaluation_mode,
|
| &breakpoint_set_cmdlist,
|
| &breakpoint_show_cmdlist);
|
|
|
| @@ -14122,6 +16429,58 @@ The breakpoint will stop execution of the inferior whenever it executes\n\
|
| an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
|
| range (including START-LOCATION and END-LOCATION)."));
|
|
|
| + c = add_com ("dprintf", class_breakpoint, dprintf_command, _("\
|
| +Set a dynamic printf at specified line or function.\n\
|
| +dprintf location,format string,arg1,arg2,...\n\
|
| +location may be a line number, function name, or \"*\" and an address.\n\
|
| +If a line number is specified, break at start of code for that line.\n\
|
| +If a function is specified, break at start of code for that function.\n\
|
| +"));
|
| + set_cmd_completer (c, location_completer);
|
| +
|
| + add_setshow_enum_cmd ("dprintf-style", class_support,
|
| + dprintf_style_enums, &dprintf_style, _("\
|
| +Set the style of usage for dynamic printf."), _("\
|
| +Show the style of usage for dynamic printf."), _("\
|
| +This setting chooses how GDB will do a dynamic printf.\n\
|
| +If the value is \"gdb\", then the printing is done by GDB to its own\n\
|
| +console, as with the \"printf\" command.\n\
|
| +If the value is \"call\", the print is done by calling a function in your\n\
|
| +program; by default printf(), but you can choose a different function or\n\
|
| +output stream by setting dprintf-function and dprintf-channel."),
|
| + update_dprintf_commands, NULL,
|
| + &setlist, &showlist);
|
| +
|
| + dprintf_function = xstrdup ("printf");
|
| + add_setshow_string_cmd ("dprintf-function", class_support,
|
| + &dprintf_function, _("\
|
| +Set the function to use for dynamic printf"), _("\
|
| +Show the function to use for dynamic printf"), NULL,
|
| + update_dprintf_commands, NULL,
|
| + &setlist, &showlist);
|
| +
|
| + dprintf_channel = xstrdup ("");
|
| + add_setshow_string_cmd ("dprintf-channel", class_support,
|
| + &dprintf_channel, _("\
|
| +Set the channel to use for dynamic printf"), _("\
|
| +Show the channel to use for dynamic printf"), NULL,
|
| + update_dprintf_commands, NULL,
|
| + &setlist, &showlist);
|
| +
|
| + add_setshow_boolean_cmd ("disconnected-dprintf", no_class,
|
| + &disconnected_dprintf, _("\
|
| +Set whether dprintf continues after GDB disconnects."), _("\
|
| +Show whether dprintf continues after GDB disconnects."), _("\
|
| +Use this to let dprintf commands continue to hit and produce output\n\
|
| +even if GDB disconnects or detaches from the target."),
|
| + NULL,
|
| + NULL,
|
| + &setlist, &showlist);
|
| +
|
| + add_com ("agent-printf", class_vars, agent_printf_command, _("\
|
| +agent-printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
|
| +(target agent only) This is useful for formatted output in user-defined commands."));
|
| +
|
| automatic_hardware_breakpoints = 1;
|
|
|
| observer_attach_about_to_proceed (breakpoint_about_to_proceed);
|
|
|