/* Everything about breakpoints, for GDB.
- Copyright (C) 1986-2012 Free Software Foundation, Inc.
+ Copyright (C) 1986-2013 Free Software Foundation, Inc.
This file is part of GDB.
#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"
#include "mi/mi-common.h"
#include "python/python.h"
+/* Enums for exception-handling support. */
+enum exception_event_kind
+{
+ EX_EVENT_THROW,
+ EX_EVENT_CATCH
+};
+
/* Prototypes for local functions. */
static void enable_delete_command (char *, int);
static void create_breakpoints_sal_default (struct gdbarch *,
struct linespec_result *,
struct linespec_sals *,
- char *, enum bptype,
+ char *, char *, enum bptype,
enum bpdisp, int, int,
int,
const struct breakpoint_ops *,
- int, int, int);
+ int, int, int, unsigned);
static void decode_linespec_default (struct breakpoint *, char **,
struct symtabs_and_lines *);
static void trace_pass_command (char *, int);
+static void set_tracepoint_count (int num);
+
static int is_masked_watchpoint (const struct breakpoint *b);
+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. */
-static struct breakpoint_ops base_breakpoint_ops;
+struct breakpoint_ops base_breakpoint_ops;
/* The breakpoint_ops structure to be inherited by all breakpoint_ops
that are implemented on top of software or hardware breakpoints
/* 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
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 *const 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"),
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);
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) \
\f
+/* 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)
{
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. */
}
}
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;
{
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"));
}
}
}
- breakpoints_changed ();
+ mark_breakpoint_modified (b);
+
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)
+ xsnprintf (location, sizeof (location), "%d", b->number);
+ else
+ xsnprintf (location, sizeof (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
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;
}
decref_counted_command_line (&b->commands);
b->commands = alloc_counted_command_line (commands);
- breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
incref_counted_command_line (info->cmd);
decref_counted_command_line (&b->commands);
b->commands = info->cmd;
- breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
}
/* 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
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,
}
\f
+/* 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
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
}
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);
}
}
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR addr;
- int len, type;
+ int type;
struct bp_location *loc, **tmp;
addr = value_address (v);
- len = TYPE_LENGTH (value_type (v));
type = hw_write;
if (b->base.type == bp_read_watchpoint)
type = hw_read;
loc->pspace = frame_pspace;
loc->address = addr;
- loc->length = len;
+ loc->length = TYPE_LENGTH (value_type (v));
loc->watchpoint_type = type;
}
}
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.
insert_bp_location (struct bp_location *bl,
struct ui_file *tmp_error_stream,
int *disabled_breaks,
- int *hw_breakpoint_error)
+ int *hw_breakpoint_error,
+ int *hw_bp_error_explained_already)
{
int val = 0;
+ char *hw_bp_err_string = NULL;
+ struct gdb_exception e;
- 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)
{
|| !(section_is_overlay (bl->section)))
{
/* No overlay handling: just set the breakpoint. */
-
- val = bl->owner->ops->insert_location (bl);
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ val = bl->owner->ops->insert_location (bl);
+ }
+ if (e.reason < 0)
+ {
+ val = 1;
+ hw_bp_err_string = (char *) e.message;
+ }
}
else
{
if (section_is_mapped (bl->section))
{
/* Yes. This overlay section is mapped into memory. */
- val = bl->owner->ops->insert_location (bl);
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ val = bl->owner->ops->insert_location (bl);
+ }
+ if (e.reason < 0)
+ {
+ val = 1;
+ hw_bp_err_string = (char *) e.message;
+ }
}
else
{
{
if (bl->loc_type == bp_loc_hardware_breakpoint)
{
- *hw_breakpoint_error = 1;
- fprintf_unfiltered (tmp_error_stream,
- "Cannot insert hardware "
- "breakpoint %d.\n",
- bl->owner->number);
+ *hw_breakpoint_error = 1;
+ *hw_bp_error_explained_already = hw_bp_err_string != NULL;
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert hardware breakpoint %d%s",
+ bl->owner->number, hw_bp_err_string ? ":" : ".\n");
+ if (hw_bp_err_string)
+ fprintf_unfiltered (tmp_error_stream, "%s.\n", hw_bp_err_string);
}
else
{
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;
+ int hw_bp_details_reported = 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, &hw_bp_details_reported);
+ 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
int val = 0;
int disabled_breaks = 0;
int hw_breakpoint_error = 0;
+ int hw_bp_error_explained_already = 0;
struct ui_file *tmp_error_stream = mem_fileopen ();
struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
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
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)
+ 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);
+ &hw_breakpoint_error, &hw_bp_error_explained_already);
if (val)
error_flag = val;
}
{
/* If a hardware breakpoint or watchpoint was inserted, add a
message about possibly exhausted resources. */
- if (hw_breakpoint_error)
+ if (hw_breakpoint_error && !hw_bp_error_explained_already)
{
fprintf_unfiltered (tmp_error_stream,
"Could not insert hardware breakpoints:\n\
if (bl->pspace != inf->pspace)
continue;
+ if (bl->owner->type == bp_dprintf)
+ continue;
+
if (bl->inserted)
{
val = remove_breakpoint (bl, mark_uninserted);
struct bp_location *bl, **blp_tmp;
int val;
struct ui_file *tmp_error_stream;
- int dummy1 = 0, dummy2 = 0;
+ int dummy1 = 0, dummy2 = 0, dummy3 = 0;
struct inferior *inf;
struct thread_info *tp;
if (bl->inserted)
{
bl->inserted = 0;
- val = insert_bp_location (bl, tmp_error_stream, &dummy1, &dummy2);
+ val = insert_bp_location (bl, tmp_error_stream, &dummy1, &dummy2, &dummy3);
if (val != 0)
{
do_cleanups (old_chain);
/* 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;
}
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;
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;
/* Install a master breakpoint on the unwinder's debug hook. */
-void
+static void
create_exception_master_breakpoint (void)
{
struct objfile *objfile;
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;
/* 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);
}
int
-detach_breakpoints (int pid)
+detach_breakpoints (ptid_t ptid)
{
struct bp_location *bl, **blp_tmp;
int val = 0;
struct cleanup *old_chain = save_inferior_ptid ();
struct inferior *inf = current_inferior ();
- if (pid == PIDGET (inferior_ptid))
+ if (PIDGET (ptid) == PIDGET (inferior_ptid))
error (_("Cannot detach breakpoints of inferior_ptid"));
/* Set inferior_ptid; remove_breakpoint_1 uses this global. */
- inferior_ptid = pid_to_ptid (pid);
+ inferior_ptid = ptid;
ALL_BP_LOCATIONS (bl, blp_tmp)
{
if (bl->pspace != inf->pspace)
/* If breakpoint locations are shared across processes, then there's
nothing to do. */
- if (gdbarch_has_global_breakpoints (target_gdbarch))
+ if (gdbarch_has_global_breakpoints (target_gdbarch ()))
return;
ALL_BP_LOCATIONS (bl, blp_tmp)
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
(gdb) tar rem :9999 # remote Windows gdbserver.
*/
+ case bp_step_resume:
+
+ /* Also remove step-resume breakpoints. */
+
delete_breakpoint (b);
break;
in breakpoint.h. */
int
-ep_is_catchpoint (struct breakpoint *ep)
+is_catchpoint (struct breakpoint *ep)
{
return (ep->type == bp_catchpoint);
}
return NULL;
}
+/* See breakpoint.h. */
+
+enum bpstat_signal_value
+bpstat_explains_signal (bpstat bsp)
+{
+ enum bpstat_signal_value result = BPSTAT_SIGNAL_NO;
+
+ for (; bsp != NULL; bsp = bsp->next)
+ {
+ /* Ensure that, if we ever entered this loop, then we at least
+ return BPSTAT_SIGNAL_HIDE. */
+ enum bpstat_signal_value newval = BPSTAT_SIGNAL_HIDE;
+
+ if (bsp->breakpoint_at != NULL)
+ newval = bsp->breakpoint_at->ops->explains_signal (bsp->breakpoint_at);
+
+ if (newval > result)
+ result = newval;
+ }
+
+ return result;
+}
+
/* Put in *NUM the breakpoint number of the first breakpoint we are
stopped at. *BSP upon return is a bpstat which points to the
remaining breakpoints stopped at (but which is not guaranteed to be
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;
else if (b->ignore_count > 0)
{
b->ignore_count--;
- annotate_ignore_count_change ();
bs->stop = 0;
/* Increase the hit count even though we don't stop. */
++(b->hit_count);
if (b->type == bp_hardware_watchpoint && bl != b->loc)
break;
- if (bl->shlib_disabled)
+ if (!bl->enabled || bl->shlib_disabled)
continue;
if (!bpstat_check_location (bl, aspace, bp_addr, ws))
}
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:
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);
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;
+
+ 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++;
+ }
+
+ 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. */
static void
if (b->display_canonical)
ui_out_field_string (uiout, "what", b->addr_string);
- else if (loc && loc->source_file)
+ else if (loc && loc->symtab)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
ui_out_text (uiout, "at ");
}
- ui_out_field_string (uiout, "file", loc->source_file);
+ ui_out_field_string (uiout, "file",
+ symtab_to_filename_for_display (loc->symtab));
ui_out_text (uiout, ":");
-
+
if (ui_out_is_mi_like_p (uiout))
- {
- struct symtab_and_line sal = find_pc_line (loc->address, 0);
- char *fullname = symtab_to_fullname (sal.symtab);
-
- if (fullname)
- ui_out_field_string (uiout, "fullname", fullname);
- }
+ ui_out_field_string (uiout, "fullname",
+ symtab_to_fullname (loc->symtab));
ui_out_field_int (uiout, "line", loc->line_number);
}
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);
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);
}
{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"},
{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"},
};
- if (((int) type >= (sizeof (bptypes) / sizeof (bptypes[0])))
- || ((int) type != bptypes[(int) type].type))
- internal_error (__FILE__, __LINE__,
- _("bptypes table does not describe type #%d."),
- (int) type);
+ if (((int) type >= (sizeof (bptypes) / sizeof (bptypes[0])))
+ || ((int) type != bptypes[(int) type].type))
+ internal_error (__FILE__, __LINE__,
+ _("bptypes table does not describe type #%d."),
+ (int) type);
+
+ return bptypes[(int) type].description;
+}
+
+DEF_VEC_I(int);
+
+/* For MI, output a field named 'thread-groups' with a list as the value.
+ For CLI, prefix the list with the string 'inf'. */
+
+static void
+output_thread_groups (struct ui_out *uiout,
+ const char *field_name,
+ VEC(int) *inf_num,
+ int mi_only)
+{
+ struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (uiout,
+ field_name);
+ int is_mi = ui_out_is_mi_like_p (uiout);
+ int inf;
+ int i;
+
+ /* For backward compatibility, don't display inferiors in CLI unless
+ there are several. Always display them for MI. */
+ if (!is_mi && mi_only)
+ return;
+
+ for (i = 0; VEC_iterate (int, inf_num, i, inf); ++i)
+ {
+ if (is_mi)
+ {
+ char mi_group[10];
+
+ xsnprintf (mi_group, sizeof (mi_group), "i%d", inf);
+ ui_out_field_string (uiout, NULL, mi_group);
+ }
+ else
+ {
+ if (i == 0)
+ ui_out_text (uiout, " inf ");
+ else
+ ui_out_text (uiout, ", ");
+
+ ui_out_text (uiout, plongest (inf));
+ }
+ }
- return bptypes[(int) type].description;
+ do_cleanups (back_to);
}
/* Print B to gdb_stdout. */
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:
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:
}
- /* For backward compatibility, don't display inferiors unless there
- are several. */
- if (loc != NULL
- && !header_of_multiple
- && (allflag
- || (!gdbarch_has_global_breakpoints (target_gdbarch)
- && (number_of_program_spaces () > 1
- || number_of_inferiors () > 1)
- /* LOC is for existing B, it cannot be in
- moribund_locations and thus having NULL OWNER. */
- && loc->owner->type != bp_catchpoint)))
+ if (loc != NULL && !header_of_multiple)
{
struct inferior *inf;
- int first = 1;
+ VEC(int) *inf_num = NULL;
+ int mi_only = 1;
- for (inf = inferior_list; inf != NULL; inf = inf->next)
+ ALL_INFERIORS (inf)
{
if (inf->pspace == loc->pspace)
- {
- if (first)
- {
- first = 0;
- ui_out_text (uiout, " inf ");
- }
- else
- ui_out_text (uiout, ", ");
- ui_out_text (uiout, plongest (inf->num));
- }
+ VEC_safe_push (int, inf_num, inf->num);
}
+
+ /* For backward compatibility, don't display inferiors in CLI unless
+ there are several. Always display for MI. */
+ if (allflag
+ || (!gdbarch_has_global_breakpoints (target_gdbarch ())
+ && (number_of_program_spaces () > 1
+ || number_of_inferiors () > 1)
+ /* LOC is for existing B, it cannot be in
+ moribund_locations and thus having NULL OWNER. */
+ && loc->owner->type != bp_catchpoint))
+ mi_only = 0;
+ output_thread_groups (uiout, "thread-groups", inf_num, mi_only);
+ VEC_free (int, inf_num);
}
if (!part_of_multiple)
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");
}
ui_out_text (uiout, "\n");
}
- if (!part_of_multiple && b->hit_count)
+ if (!part_of_multiple)
{
- /* FIXME should make an annotation for this. */
- if (ep_is_catchpoint (b))
- ui_out_text (uiout, "\tcatchpoint");
- else if (is_tracepoint (b))
- ui_out_text (uiout, "\ttracepoint");
- else
- ui_out_text (uiout, "\tbreakpoint");
- ui_out_text (uiout, " already hit ");
- ui_out_field_int (uiout, "times", b->hit_count);
- if (b->hit_count == 1)
- ui_out_text (uiout, " time\n");
+ if (b->hit_count)
+ {
+ /* FIXME should make an annotation for this. */
+ if (is_catchpoint (b))
+ ui_out_text (uiout, "\tcatchpoint");
+ else if (is_tracepoint (b))
+ ui_out_text (uiout, "\ttracepoint");
+ else
+ ui_out_text (uiout, "\tbreakpoint");
+ ui_out_text (uiout, " already hit ");
+ ui_out_field_int (uiout, "times", b->hit_count);
+ if (b->hit_count == 1)
+ ui_out_text (uiout, " time\n");
+ else
+ ui_out_text (uiout, " times\n");
+ }
else
- ui_out_text (uiout, " times\n");
+ {
+ /* Output the count also if it is zero, but only if this is mi. */
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "times", b->hit_count);
+ }
}
-
- /* Output the count also if it is zero, but only if this is mi.
- FIXME: Should have a better test for this. */
- if (ui_out_is_mi_like_p (uiout))
- if (!part_of_multiple && b->hit_count == 0)
- ui_out_field_int (uiout, "times", b->hit_count);
if (!part_of_multiple && b->ignore_count)
{
ui_out_text (uiout, " bytes\n");
}
}
-
+
l = b->commands ? b->commands->commands : NULL;
if (!part_of_multiple && l)
{
ui_out_field_int (uiout, "pass", t->pass_count);
ui_out_text (uiout, " \n");
}
+
+ /* Don't display it when tracepoint or tracepoint location is
+ pending. */
+ if (!header_of_multiple && loc != NULL && !loc->shlib_disabled)
+ {
+ annotate_field (11);
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "installed",
+ loc->inserted ? "y" : "n");
+ else
+ {
+ if (loc->inserted)
+ ui_out_text (uiout, "\t");
+ else
+ ui_out_text (uiout, "\tnot ");
+ ui_out_text (uiout, "installed on target\n");
+ }
+ }
}
if (ui_out_is_mi_like_p (uiout) && !part_of_multiple)
breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
struct address_space *aspace2, CORE_ADDR addr2)
{
- return ((gdbarch_has_global_breakpoints (target_gdbarch)
+ return ((gdbarch_has_global_breakpoints (target_gdbarch ())
|| aspace1 == aspace2)
&& addr1 == addr2);
}
int len1, struct address_space *aspace2,
CORE_ADDR addr2)
{
- return ((gdbarch_has_global_breakpoints (target_gdbarch)
+ return ((gdbarch_has_global_breakpoints (target_gdbarch ())
|| aspace1 == aspace2)
&& addr2 >= addr1 && addr2 < addr1 + len1);
}
loc->ops = ops;
loc->owner = owner;
loc->cond = NULL;
+ loc->cond_bytecode = NULL;
loc->shlib_disabled = 0;
loc->enabled = 1;
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:
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:
{
int is_gnu_ifunc;
const char *function_name;
+ CORE_ADDR func_addr;
find_pc_partial_function_gnu_ifunc (loc->address, &function_name,
- NULL, NULL, &is_gnu_ifunc);
+ &func_addr, NULL, &is_gnu_ifunc);
if (is_gnu_ifunc && !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;
}
}
program space. */
if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint)
b->pspace = sal.pspace;
-
- breakpoints_changed ();
}
/* set_raw_breakpoint is a low level routine for allocating and
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;
}
}
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;
ptid_get_pid (c->forked_inferior_pid));
ui_out_spaces (uiout, 1);
}
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "fork");
}
/* Implement the "print_mention" breakpoint_ops method for fork
ptid_get_pid (c->forked_inferior_pid));
ui_out_spaces (uiout, 1);
}
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "vfork");
}
/* Implement the "print_mention" breakpoint_ops method for vfork
}
ui_out_field_string (uiout, "what", msg);
xfree (msg);
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type",
+ self->is_load ? "load" : "unload");
}
static void
static struct breakpoint_ops catch_solib_breakpoint_ops;
-/* A helper function that does all the work for "catch load" and
- "catch unload". */
+/* Shared helper function (MI and CLI) for creating and installing
+ a shared object event catchpoint. If IS_LOAD is non-zero then
+ the events to be caught are load events, otherwise they are
+ unload events. If IS_TEMP is non-zero the catchpoint is a
+ temporary one. If ENABLED is non-zero the catchpoint is
+ created in an enabled state. */
-static void
-catch_load_or_unload (char *arg, int from_tty, int is_load,
- struct cmd_list_element *command)
+void
+add_solib_catchpoint (char *arg, int is_load, int is_temp, int enabled)
{
struct solib_catchpoint *c;
struct gdbarch *gdbarch = get_current_arch ();
- int tempflag;
- regex_t compiled;
struct cleanup *cleanup;
- tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
-
if (!arg)
arg = "";
arg = skip_spaces (arg);
}
c->is_load = is_load;
- init_catchpoint (&c->base, gdbarch, tempflag, NULL,
+ init_catchpoint (&c->base, gdbarch, is_temp, NULL,
&catch_solib_breakpoint_ops);
+ c->base.enable_state = enabled ? bp_enabled : bp_disabled;
+
discard_cleanups (cleanup);
install_breakpoint (0, &c->base, 1);
}
+/* 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)
+{
+ int tempflag;
+ const int enabled = 1;
+
+ tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+ add_solib_catchpoint (arg, is_load, tempflag, enabled);
+}
+
static void
catch_load_command_1 (char *arg, int from_tty,
struct cmd_list_element *command)
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. */
{
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;
{
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
{
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;
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
ptid_t ptid;
struct target_waitstatus last;
struct syscall s;
- char *syscall_id;
get_last_target_status (&ptid, &last);
else
ui_out_field_string (uiout, "what", "<any syscall>");
ui_out_text (uiout, "\" ");
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "syscall");
}
/* Implement the "print_mention" breakpoint_ops method for syscall
not NULL, then store it in the breakpoint. OPS, if not NULL, is
the breakpoint_ops structure associated to the catchpoint. */
-static void
+void
init_catchpoint (struct breakpoint *b,
struct gdbarch *gdbarch, int tempflag,
char *cond_string,
{
add_to_breakpoint_chain (b);
set_breakpoint_number (internal, b);
+ if (is_tracepoint (b))
+ set_tracepoint_count (breakpoint_count);
if (!internal)
mention (b);
observer_notify_breakpoint_created (b);
ui_out_field_string (uiout, "what", c->exec_pathname);
ui_out_text (uiout, "\" ");
}
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "exec");
}
static void
{
struct breakpoint *b;
- /* If FRAME_ID is valid, it should be a real frame, not an inlined
- one. */
- gdb_assert (!frame_id_inlined_p (frame_id));
+ /* If FRAME_ID is valid, it should be a real frame, not an inlined or
+ tail-called one. */
+ gdb_assert (!frame_id_artificial_p (frame_id));
b = set_raw_breakpoint (gdbarch, sal, type, &momentary_breakpoint_ops);
b->enable_state = bp_enabled;
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
-
- if (orig->loc->source_file != NULL)
- copy->loc->source_file = xstrdup (orig->loc->source_file);
-
+ copy->loc->probe = orig->loc->probe;
copy->loc->line_number = orig->loc->line_number;
+ copy->loc->symtab = orig->loc->symtab;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
copy->pspace = orig->pspace;
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;
-
- if (sal->symtab != NULL)
- loc->source_file = xstrdup (sal->symtab->filename);
loc->line_number = sal->line;
+ loc->symtab = sal->symtab;
set_breakpoint_location_function (loc,
sal->explicit_pc || sal->explicit_line);
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."));
+
+ gdb_assert (printf_line != NULL);
+ /* Manufacture a printf/continue sequence. */
+ {
+ 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
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, int display_canonical)
+ int enabled, int internal, unsigned flags,
+ int display_canonical)
{
int i;
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;
+ if ((flags & CREATE_BREAKPOINT_FLAGS_INSERTED) != 0)
+ b->loc->inserted = 1;
+
if (type == bp_static_tracepoint)
{
struct tracepoint *t = (struct tracepoint *) b;
else
{
loc = add_location_to_breakpoint (b, &sal);
+ if ((flags & CREATE_BREAKPOINT_FLAGS_INSERTED) != 0)
+ loc->inserted = 1;
}
if (bp_loc_is_permanent (loc))
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)
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,
- int enabled, int internal, int display_canonical)
+ int enabled, int internal, unsigned flags,
+ int display_canonical)
{
struct breakpoint *b;
struct cleanup *old_chain;
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,
- enabled, internal, display_canonical);
+ enabled, internal, flags,
+ display_canonical);
discard_cleanups (old_chain);
install_breakpoint (internal, b, 0);
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,
- int enabled, int internal)
+ int enabled, int internal, unsigned flags)
{
int i;
struct linespec_sals *lsal;
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,
+ from_tty, enabled, internal, flags,
canonical->special_display);
discard_cleanups (inner);
}
parse_breakpoint_sals (char **address,
struct linespec_result *canonical)
{
- char *addr_start = *address;
-
/* If no arg given, or if first arg is 'if ', use the default
breakpoint. */
if ((*address) == NULL
{
struct linespec_sals lsal;
struct symtab_and_line sal;
+ CORE_ADDR pc;
init_sal (&sal); /* Initialize to zeroes. */
lsal.sals.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
/* Set sal's pspace, pc, symtab, and line to the values
- corresponding to the last call to print_frame_info. */
+ corresponding to the last call to print_frame_info.
+ Be sure to reinitialize LINE with NOTCURRENT == 0
+ as the breakpoint line number is inappropriate otherwise.
+ find_pc_line would adjust PC, re-set it back. */
get_last_displayed_sal (&sal);
- sal.section = find_pc_overlay (sal.pc);
+ pc = sal.pc;
+ sal = find_pc_line (pc, 0);
/* "break" without arguments is equivalent to "break *PC"
where PC is the last displayed codepoint's address. So
make sure to set sal.explicit_pc to prevent GDB from
trying to expand the list of sals to include all other
instances with the same symtab and line. */
+ sal.pc = pc;
sal.explicit_pc = 1;
lsal.sals.sals[0] = sal;
}
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);
}
}
}
}
+/* Issue an invalid thread ID error. */
+
+static void ATTRIBUTE_NORETURN
+invalid_thread_id_error (int id)
+{
+ error (_("Unknown thread %d."), id);
+}
+
/* Given TOK, a string specification of condition and thread, as
accepted by the 'break' command, extract the condition
string and thread number and set *COND_STRING and *THREAD.
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;
+ *task = 0;
+ *rest = NULL;
+
while (tok && *tok)
{
char *end_tok;
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);
if (tok == tmptok)
error (_("Junk after thread keyword."));
if (!valid_thread_id (*thread))
- error (_("Unknown thread %d."), *thread);
+ invalid_thread_id_error (*thread);
}
else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
{
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."));
}
{
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;
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,
enum auto_boolean pending_break_support,
const struct breakpoint_ops *ops,
- int from_tty, int enabled, int internal)
+ int from_tty, int enabled, int internal,
+ unsigned flags)
{
volatile struct gdb_exception e;
char *copy_arg = NULL;
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;
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;
+
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
{
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);
+ }
}
ops->create_breakpoints_sal (gdbarch, &canonical, lsal,
- cond_string, type_wanted,
+ cond_string, extra_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
- from_tty, enabled, internal);
+ from_tty, enabled, internal, flags);
}
else
{
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;
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 */);
+ 0 /* internal */,
+ 0);
}
/* Helper function for break_command_1 and disassemble_command. */
{
if (!find_line_pc (sal->symtab, sal->line, &pc))
error (_("No line %d in file \"%s\"."),
- sal->line, sal->symtab->filename);
+ sal->line, symtab_to_filename_for_display (sal->symtab));
sal->pc = pc;
/* If this SAL corresponds to a breakpoint inserted using a line
badInput = !isdigit (*arg); /* not a line number */
}
- if (badInput)
- printf_filtered (_("Usage: stop at <line>\n"));
- else
- break_command_1 (arg, 0, from_tty);
+ if (badInput)
+ printf_filtered (_("Usage: stop at <line>\n"));
+ else
+ break_command_1 (arg, 0, 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. */
+
+static 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
const struct target_waitstatus *ws)
{
if (ws->kind != TARGET_WAITKIND_STOPPED
- || ws->value.sig != TARGET_SIGNAL_TRAP)
+ || ws->value.sig != GDB_SIGNAL_TRAP)
return 0;
return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
{
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);
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);
case BINOP_RANGE:
case TERNOP_COND:
case TERNOP_SLICE:
- case TERNOP_SLICE_COUNT:
case OP_LONG:
case OP_DOUBLE:
case OP_LAST:
case OP_COMPLEX:
case OP_STRING:
- case OP_BITSTRING:
case OP_ARRAY:
case OP_TYPE:
+ case OP_TYPEOF:
+ case OP_DECLTYPE:
case OP_NAME:
case OP_OBJC_NSSTRING:
case UNOP_COMPLEMENT:
case UNOP_ADDR:
case UNOP_HIGH:
+ case UNOP_CAST:
+
+ case UNOP_CAST_TYPE:
+ case UNOP_REINTERPRET_CAST:
+ case UNOP_DYNAMIC_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
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;
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)
{
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. */
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;
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 = ");
}
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;
volatile struct gdb_exception e;
struct breakpoint *b, *scope_breakpoint = NULL;
struct expression *exp;
- struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
+ const struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
struct value *val, *mark, *result;
struct frame_info *frame;
char *exp_start = NULL;
/* Check if the thread actually exists. */
if (!valid_thread_id (thread))
- error (_("Unknown thread %d."), thread);
+ invalid_thread_id_error (thread);
}
else if (toklen == 4 && !strncmp (tok, "mask", 4))
{
/* 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
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'. */
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. */
{
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;
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
if (b->loc)
*last_loc = b->loc;
if (strstr (b->addr_string, "throw") != NULL)
- ui_out_field_string (uiout, "what", "exception throw");
+ {
+ ui_out_field_string (uiout, "what", "exception throw");
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "throw");
+ }
else
- ui_out_field_string (uiout, "what", "exception catch");
+ {
+ ui_out_field_string (uiout, "what", "exception catch");
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "catch");
+ }
}
static void
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,
AUTO_BOOLEAN_TRUE /* pending */,
&gnu_v3_exception_catchpoint_ops, from_tty,
1 /* enabled */,
- 0 /* internal */);
+ 0 /* internal */,
+ 0);
return 1;
}
the number 0. */
if (ua < ub)
return -1;
- return ub > ub ? 1 : 0;
+ return ua > ub ? 1 : 0;
}
/* Delete breakpoints by address or line. */
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));
+ make_cleanup (xfree, sals.sals);
default_match = 0;
}
else
make_cleanup (VEC_cleanup (breakpoint_p), &found);
for (i = 0; i < sals.nelts; i++)
{
- int is_abs, sal_name_len;
+ const char *sal_fullname;
/* If exact pc given, clear bpts at that pc.
If line given (pc == 0), clear all bpts on specified line.
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);
+ sal_fullname = (sal.symtab == NULL
+ ? NULL : symtab_to_fullname (sal.symtab));
/* Find all matching breakpoints and add them to 'found'. */
ALL_BREAKPOINTS (b)
int line_match = 0;
if ((default_match || sal.explicit_line)
- && loc->source_file != NULL
- && sal.symtab != NULL
+ && loc->symtab != NULL
+ && sal_fullname != 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;
- }
+ && loc->line_number == sal.line
+ && filename_cmp (symtab_to_fullname (loc->symtab),
+ sal_fullname) == 0)
+ line_match = 1;
if (pc_match || line_match)
{
else
printf_unfiltered (_("Deleted breakpoints "));
}
- breakpoints_changed ();
for (ix = 0; VEC_iterate(breakpoint_p, found, ix, b); ix++)
{
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);
static void
download_tracepoint_locations (void)
{
- struct bp_location *bl, **blp_tmp;
+ struct breakpoint *b;
struct cleanup *old_chain;
if (!target_can_download_tracepoint ())
old_chain = save_current_space_and_thread ();
- ALL_BP_LOCATIONS (bl, blp_tmp)
+ ALL_TRACEPOINTS (b)
{
+ struct bp_location *bl;
struct tracepoint *t;
+ int bp_location_downloaded = 0;
- if (!is_tracepoint (bl->owner))
- continue;
-
- if ((bl->owner->type == bp_fast_tracepoint
+ if ((b->type == bp_fast_tracepoint
? !may_insert_fast_tracepoints
: !may_insert_tracepoints))
continue;
- /* In tracepoint, locations are _never_ duplicated, so
- should_be_inserted is equivalent to
- unduplicated_should_be_inserted. */
- if (!should_be_inserted (bl) || bl->inserted)
- continue;
+ for (bl = b->loc; bl; bl = bl->next)
+ {
+ /* In tracepoint, locations are _never_ duplicated, so
+ should_be_inserted is equivalent to
+ unduplicated_should_be_inserted. */
+ if (!should_be_inserted (bl) || bl->inserted)
+ continue;
- switch_to_program_space_and_thread (bl->pspace);
+ switch_to_program_space_and_thread (bl->pspace);
- target_download_tracepoint (bl);
+ target_download_tracepoint (bl);
- bl->inserted = 1;
- t = (struct tracepoint *) bl->owner;
- t->number_on_target = bl->owner->number;
+ bl->inserted = 1;
+ bp_location_downloaded = 1;
+ }
+ t = (struct tracepoint *) b;
+ t->number_on_target = b->number;
+ if (bp_location_downloaded)
+ observer_notify_breakpoint_modified (b);
}
do_cleanups (old_chain);
{
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. */
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
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.
&& (*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
}
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
struct bp_location **loc_first_p;
b = loc->owner;
- if (!should_be_inserted (loc)
+ if (!unduplicated_should_be_inserted (loc)
|| !breakpoint_address_is_meaningful (b)
/* Don't detect duplicate for tracepoint locations because they are
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)
{
*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;
}
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__,
"a permanent breakpoint"));
}
- if (breakpoints_always_inserted_mode () && should_insert
+ if (breakpoints_always_inserted_mode ()
&& (have_live_inferiors ()
- || (gdbarch_has_global_breakpoints (target_gdbarch))))
- insert_breakpoint_locations ();
+ || (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 ();
}
else
{
- if (opts.addressprint || b->loc->source_file == NULL)
+ if (opts.addressprint || b->loc->symtab == NULL)
{
printf_filtered (" at ");
fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
gdb_stdout);
}
- if (b->loc->source_file)
+ if (b->loc->symtab != NULL)
{
/* If there is a single location, we can print the location
more nicely. */
if (b->loc->next == NULL)
printf_filtered (": file %s, line %d.",
- b->loc->source_file, b->loc->line_number);
+ symtab_to_filename_for_display (b->loc->symtab),
+ b->loc->line_number);
else
/* This is not ideal, but each location may have a
different file name, and this at least reflects the
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);
}
static const struct bp_location_ops bp_location_ops =
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)
+ int internal, unsigned flags)
{
internal_error_pure_virtual_called ();
}
internal_error_pure_virtual_called ();
}
-static struct breakpoint_ops base_breakpoint_ops =
+/* The default 'explains_signal' method. */
+
+static enum bpstat_signal_value
+base_breakpoint_explains_signal (struct breakpoint *b)
+{
+ return BPSTAT_SIGNAL_HIDE;
+}
+
+struct breakpoint_ops base_breakpoint_ops =
{
base_breakpoint_dtor,
base_breakpoint_allocate_location,
base_breakpoint_create_sals_from_address,
base_breakpoint_create_breakpoints_sal,
base_breakpoint_decode_linespec,
+ base_breakpoint_explains_signal
};
/* Default breakpoint_ops methods. */
struct breakpoint *b = bl->owner;
if (ws->kind != TARGET_WAITKIND_STOPPED
- || ws->value.sig != TARGET_SIGNAL_TRAP)
+ || ws->value.sig != GDB_SIGNAL_TRAP)
return 0;
if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
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);
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)
+ int internal, unsigned flags)
{
create_breakpoints_sal_default (gdbarch, canonical, lsal,
- cond_string, type_wanted,
+ cond_string, extra_string,
+ type_wanted,
disposition, thread, task,
ignore_count, ops, from_tty,
- enabled, internal);
+ enabled, internal, flags);
}
static void
/* 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
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)
+ int internal, unsigned flags)
{
create_breakpoints_sal_default (gdbarch, canonical, lsal,
- cond_string, type_wanted,
+ cond_string, extra_string,
+ type_wanted,
disposition, thread, task,
ignore_count, ops, from_tty,
- enabled, internal);
+ enabled, internal, flags);
}
static void
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'). */
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)
+ int internal, unsigned flags)
{
int i;
tp = XCNEW (struct tracepoint);
init_breakpoint_sal (&tp->base, gdbarch, expanded,
addr_string, NULL,
- cond_string, type_wanted, disposition,
+ cond_string, extra_string,
+ type_wanted, disposition,
thread, task, ignore_count, ops,
- from_tty, enabled, internal,
+ 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
struct tracepoint *tp = (struct tracepoint *) b;
struct static_tracepoint_marker marker;
CORE_ADDR pc;
- int i;
pc = sal.pc;
if (sal.line)
SYMBOL_PRINT_NAME (sym));
ui_out_text (uiout, " at ");
}
- ui_out_field_string (uiout, "file", sal2.symtab->filename);
+ ui_out_field_string (uiout, "file",
+ symtab_to_filename_for_display (sal2.symtab));
ui_out_text (uiout, ":");
if (ui_out_is_mi_like_p (uiout))
{
- char *fullname = symtab_to_fullname (sal2.symtab);
+ const char *fullname = symtab_to_fullname (sal2.symtab);
- if (fullname)
- ui_out_field_string (uiout, "fullname", fullname);
+ ui_out_field_string (uiout, "fullname", fullname);
}
ui_out_field_int (uiout, "line", sal2.line);
ui_out_text (uiout, "\n");
b->loc->line_number = sal2.line;
-
- xfree (b->loc->source_file);
- if (sym)
- b->loc->source_file = xstrdup (sal2.symtab->filename);
- else
- b->loc->source_file = NULL;
+ b->loc->symtab = sym != NULL ? sal2.symtab : NULL;
xfree (b->addr_string);
b->addr_string = xstrprintf ("%s:%d",
- sal2.symtab->filename,
+ symtab_to_filename_for_display (sal2.symtab),
b->loc->line_number);
/* Might be nice to check if function changed, and warn if
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)
resolve_sal_pc (&sals.sals[i]);
if (b->condition_not_parsed && s && s[0])
{
- char *cond_string = 0;
- int thread = -1;
- int task = 0;
+ char *cond_string, *extra_string;
+ int thread, task;
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;
}
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)
+ 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);
+ enabled, internal, flags);
}
/* Decode the line represented by S by calling decode_line_full. This is the
create_longjmp_master_breakpoint ();
create_std_terminate_master_breakpoint ();
create_exception_master_breakpoint ();
-
- /* While we're at it, reset the skip list too. */
- skip_re_set ();
}
\f
/* Reset the thread number of this breakpoint:
"crossings of breakpoint %d."),
count, bptnum);
}
- breakpoints_changed ();
observer_notify_breakpoint_modified (b);
return;
}
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))
{
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))
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))
{
bpt->disposition = disposition;
bpt->enable_count = count;
update_global_location_list (1);
- breakpoints_changed ();
-
+
observer_notify_breakpoint_modified (bpt);
}
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))
GDB itself. */
static void
-invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
+invalidate_bp_value_on_memory_change (struct inferior *inferior,
+ CORE_ADDR addr, ssize_t len,
const bfd_byte *data)
{
struct breakpoint *bp;
}
}
-/* 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
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
}
/* 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
- = (list == NULL) ? NULL : complete_on_enum (list, text, word);
+ VEC (char_ptr) *retlist
+ = (list == NULL) ? NULL : complete_on_enum (list, word, word);
xfree (list);
return retlist;
set_internalvar_integer (lookup_internalvar ("tpnum"), num);
}
-void
+static void
trace_command (char *arg, int from_tty)
{
- if (create_breakpoint (get_current_arch (),
- arg,
- NULL, 0, 1 /* parse arg */,
- 0 /* tempflag */,
- bp_tracepoint /* type_wanted */,
- 0 /* Ignore count */,
- pending_break_support,
- &tracepoint_breakpoint_ops,
- from_tty,
- 1 /* enabled */,
- 0 /* internal */))
- set_tracepoint_count (breakpoint_count);
+ 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;
+
+ create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, NULL, 1 /* parse arg */,
+ 0 /* tempflag */,
+ bp_tracepoint /* type_wanted */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ ops,
+ from_tty,
+ 1 /* enabled */,
+ 0 /* internal */, 0);
}
-void
+static void
ftrace_command (char *arg, int from_tty)
{
- if (create_breakpoint (get_current_arch (),
- arg,
- NULL, 0, 1 /* parse arg */,
- 0 /* tempflag */,
- bp_fast_tracepoint /* type_wanted */,
- 0 /* Ignore count */,
- pending_break_support,
- &tracepoint_breakpoint_ops,
- from_tty,
- 1 /* enabled */,
- 0 /* internal */))
- set_tracepoint_count (breakpoint_count);
+ create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, NULL, 1 /* parse arg */,
+ 0 /* tempflag */,
+ bp_fast_tracepoint /* type_wanted */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ &tracepoint_breakpoint_ops,
+ from_tty,
+ 1 /* enabled */,
+ 0 /* internal */, 0);
}
/* strace command implementation. Creates a static tracepoint. */
-void
+static void
strace_command (char *arg, int from_tty)
{
struct breakpoint_ops *ops;
else
ops = &tracepoint_breakpoint_ops;
- if (create_breakpoint (get_current_arch (),
- arg,
- NULL, 0, 1 /* parse arg */,
- 0 /* tempflag */,
- bp_static_tracepoint /* type_wanted */,
- 0 /* Ignore count */,
- pending_break_support,
- ops,
- from_tty,
- 1 /* enabled */,
- 0 /* internal */))
- set_tracepoint_count (breakpoint_count);
+ create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, NULL, 1 /* parse arg */,
+ 0 /* tempflag */,
+ bp_static_tracepoint /* type_wanted */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ ops,
+ from_tty,
+ 1 /* enabled */,
+ 0 /* internal */, 0);
}
/* Set up a fake reader function that gets command lines from a linked
warning (_("Uploaded tracepoint %d has no "
"source location, using raw address"),
utp->number);
- sprintf (small_buf, "*%s", hex_string (utp->addr));
+ xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (utp->addr));
addr_str = small_buf;
}
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 */,
&tracepoint_breakpoint_ops,
0 /* from_tty */,
utp->enabled /* enabled */,
- 0 /* internal */))
+ 0 /* internal */,
+ CREATE_BREAKPOINT_FLAGS_INSERTED))
return NULL;
- set_tracepoint_count (breakpoint_count);
-
/* Get the tracepoint we just created. */
tp = get_tracepoint (tracepoint_count);
gdb_assert (tp != NULL);
if (utp->pass > 0)
{
- sprintf (small_buf, "%d %d", utp->pass, tp->base.number);
+ xsnprintf (small_buf, sizeof (small_buf), "%d %d", utp->pass,
+ tp->base.number);
trace_pass_command (small_buf, 0);
}
trace_pass_set_count (struct tracepoint *tp, int count, int from_tty)
{
tp->pass_count = count;
- observer_notify_tracepoint_modified (tp->base.number);
+ observer_notify_breakpoint_modified (&tp->base);
if (from_tty)
printf_filtered (_("Setting tracepoint %d's passcount to %d\n"),
tp->base.number, count);
struct get_number_or_range_state *state,
int optional_p)
{
- extern int tracepoint_count;
struct breakpoint *t;
int tpnum;
char *instring = arg == NULL ? NULL : *arg;
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\
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)
{
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
return 0;
}
+/* Remove any references to OBJFILE which is going to be freed. */
+
+void
+breakpoint_free_objfile (struct objfile *objfile)
+{
+ struct bp_location **locp, *loc;
+
+ ALL_BP_LOCATIONS (loc, locp)
+ if (loc->symtab != NULL && loc->symtab->objfile == objfile)
+ loc->symtab = NULL;
+}
+
void
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;
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->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;
}
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+static struct cmd_list_element *enablebreaklist = NULL;
+
void
_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 (NULL,
+ catch_syscall_inferior_data_cleanup);
breakpoint_chain = 0;
/* Don't bother to call set_breakpoint_count. $bpnum isn't useful
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\
Arguments are tracepoint numbers, separated by spaces.\n\
No argument means delete all tracepoints."),
&deletelist);
+ add_alias_cmd ("tr", "tracepoints", class_trace, 1, &deletelist);
c = add_cmd ("tracepoints", class_trace, disable_trace_command, _("\
Disable specified tracepoints.\n\
&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\
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);
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);