/* Everything about breakpoints, for GDB.
- Copyright (C) 1986-2012 Free Software Foundation, Inc.
+ Copyright (C) 1986-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "value.h"
#include "command.h"
#include "inferior.h"
+#include "infrun.h"
#include "gdbthread.h"
#include "target.h"
#include "language.h"
-#include "gdb_string.h"
#include "gdb-demangle.h"
#include "filenames.h"
#include "annotate.h"
#include "gdb.h"
#include "ui-out.h"
#include "cli/cli-script.h"
-#include "gdb_assert.h"
#include "block.h"
#include "solib.h"
#include "solist.h"
#include "observer.h"
-#include "exceptions.h"
#include "memattr.h"
#include "ada-lang.h"
#include "top.h"
#include "continuations.h"
#include "stack.h"
#include "skip.h"
-#include "gdb_regex.h"
#include "ax-gdb.h"
#include "dummy-frame.h"
+#include "format.h"
+
/* readline include files */
#include "readline/readline.h"
#include "readline/history.h"
#undef savestring
#include "mi/mi-common.h"
-#include "python/python.h"
+#include "extension.h"
+
+/* Enums for exception-handling support. */
+enum exception_event_kind
+{
+ EX_EVENT_THROW,
+ EX_EVENT_RETHROW,
+ EX_EVENT_CATCH
+};
/* Prototypes for local functions. */
static void create_breakpoints_sal_default (struct gdbarch *,
struct linespec_result *,
- struct linespec_sals *,
char *, char *, enum bptype,
enum bpdisp, int, int,
int,
static struct breakpoint *
momentary_breakpoint_from_master (struct breakpoint *orig,
enum bptype type,
- const struct breakpoint_ops *ops);
+ const struct breakpoint_ops *ops,
+ int loc_enabled);
static void breakpoint_adjustment_warning (CORE_ADDR, CORE_ADDR, int, int);
struct program_space *, CORE_ADDR,
struct obj_section *, int);
-static int breakpoint_address_match (struct address_space *aspace1,
- CORE_ADDR addr1,
- struct address_space *aspace2,
- CORE_ADDR addr2);
-
static int watchpoint_locations_match (struct bp_location *loc1,
struct bp_location *loc2);
static void stopat_command (char *arg, int from_tty);
-static char *ep_parse_optional_if_clause (char **arg);
-
-static void catch_exception_command_1 (enum exception_event_kind ex_event,
- char *arg, int tempflag, int from_tty);
-
static void tcatch_command (char *arg, int from_tty);
static void detach_single_step_breakpoints (void);
-static int single_step_breakpoint_inserted_here_p (struct address_space *,
- CORE_ADDR pc);
+static int find_single_step_breakpoint (struct address_space *aspace,
+ CORE_ADDR pc);
static void free_bp_location (struct bp_location *loc);
static void incref_bp_location (struct bp_location *loc);
static struct bp_location *allocate_bp_location (struct breakpoint *bpt);
-static void update_global_location_list (int);
+/* update_global_location_list's modes of operation wrt to whether to
+ insert locations now. */
+enum ugll_insert_mode
+{
+ /* Don't insert any breakpoint locations into the inferior, only
+ remove already-inserted locations that no longer should be
+ inserted. Functions that delete a breakpoint or breakpoints
+ should specify this mode, so that deleting a breakpoint doesn't
+ have the side effect of inserting the locations of other
+ breakpoints that are marked not-inserted, but should_be_inserted
+ returns true on them.
+
+ This behavior is useful is situations close to tear-down -- e.g.,
+ after an exec, while the target still has execution, but
+ breakpoint shadows of the previous executable image should *NOT*
+ be restored to the new image; or before detaching, where the
+ target still has execution and wants to delete breakpoints from
+ GDB's lists, and all breakpoints had already been removed from
+ the inferior. */
+ UGLL_DONT_INSERT,
+
+ /* May insert breakpoints iff breakpoints_should_be_inserted_now
+ claims breakpoints should be inserted now. */
+ UGLL_MAY_INSERT,
+
+ /* Insert locations now, irrespective of
+ breakpoints_should_be_inserted_now. E.g., say all threads are
+ stopped right now, and the user did "continue". We need to
+ insert breakpoints _before_ resuming the target, but
+ UGLL_MAY_INSERT wouldn't insert them, because
+ breakpoints_should_be_inserted_now returns false at that point,
+ as no thread is running yet. */
+ UGLL_INSERT
+};
+
+static void update_global_location_list (enum ugll_insert_mode);
-static void update_global_location_list_nothrow (int);
+static void update_global_location_list_nothrow (enum ugll_insert_mode);
static int is_hardware_watchpoint (const struct breakpoint *bpt);
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);
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
static struct breakpoint_ops bkpt_probe_breakpoint_ops;
/* Dynamic printf class type. */
-static struct breakpoint_ops dprintf_breakpoint_ops;
+struct breakpoint_ops dprintf_breakpoint_ops;
+
+/* One (or perhaps two) breakpoints used for software single
+ stepping. */
+
+static void *single_step_breakpoints[2];
+static struct gdbarch *single_step_gdbarch[2];
+
+/* 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. */
value);
}
-/* If on, gdb will keep breakpoints inserted even as inferior is
- stopped, and immediately insert any new breakpoints. If off, gdb
- will insert breakpoints into inferior only when resuming it, and
- 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 enum auto_boolean always_inserted_mode = AUTO_BOOLEAN_AUTO;
+/* If on, GDB keeps breakpoints inserted even if the inferior is
+ stopped, and immediately inserts any new breakpoints as soon as
+ they're created. If off (default), GDB keeps breakpoints off of
+ the target as long as possible. That is, it delays inserting
+ breakpoints until the next resume, and removes them again when the
+ target fully stops. This is a bit safer in case GDB crashes while
+ processing user input. */
+static int always_inserted_mode = 0;
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 == AUTO_BOOLEAN_AUTO)
- fprintf_filtered (file,
- _("Always inserted breakpoint "
- "mode is %s (currently %s).\n"),
- value,
- breakpoints_always_inserted_mode () ? "on" : "off");
- else
- fprintf_filtered (file, _("Always inserted breakpoint mode is %s.\n"),
- value);
+ fprintf_filtered (file, _("Always inserted breakpoint mode is %s.\n"),
+ value);
}
+/* See breakpoint.h. */
+
int
-breakpoints_always_inserted_mode (void)
+breakpoints_should_be_inserted_now (void)
{
- return (always_inserted_mode == AUTO_BOOLEAN_TRUE
- || (always_inserted_mode == AUTO_BOOLEAN_AUTO && non_stop));
+ if (gdbarch_has_global_breakpoints (target_gdbarch ()))
+ {
+ /* If breakpoints are global, they should be inserted even if no
+ thread under gdb's control is running, or even if there are
+ no threads under GDB's control yet. */
+ return 1;
+ }
+ else if (target_has_execution)
+ {
+ if (always_inserted_mode)
+ {
+ /* The user wants breakpoints inserted even if all threads
+ are stopped. */
+ return 1;
+ }
+
+ if (threads_are_executing ())
+ return 1;
+ }
+ return 0;
}
static const char condition_evaluation_both[] = "host or target";
}
/* Do the update. */
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
return;
}
else
{
- char *arg = exp;
+ const char *arg = exp;
/* I don't know if it matters whether this is the string the user
typed in or the decompiled expression. */
}
mark_breakpoint_modified (b);
- breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
/* Completion for the "condition" command. */
static VEC (char_ptr) *
-condition_completer (struct cmd_list_element *cmd, char *text, char *word)
+condition_completer (struct cmd_list_element *cmd,
+ const char *text, const char *word)
{
- char *space;
+ const char *space;
- text = skip_spaces (text);
- space = skip_to_space (text);
+ text = skip_spaces_const (text);
+ space = skip_to_space_const (text);
if (*space == '\0')
{
int len;
len = strlen (text);
ALL_BREAKPOINTS (b)
- {
- int single = b->loc->next == NULL;
- struct bp_location *loc;
- int count = 1;
-
- for (loc = b->loc; loc; loc = loc->next)
- {
- char location[50];
-
- if (single)
- sprintf (location, "%d", b->number);
- else
- sprintf (location, "%d.%d", b->number, count);
+ {
+ char number[50];
- if (strncmp (location, text, len) == 0)
- VEC_safe_push (char_ptr, result, xstrdup (location));
+ xsnprintf (number, sizeof (number), "%d", b->number);
- ++count;
- }
- }
+ if (strncmp (number, text, len) == 0)
+ VEC_safe_push (char_ptr, result, xstrdup (number));
+ }
return result;
}
/* We're completing the expression part. */
- text = skip_spaces (space);
+ text = skip_spaces_const (space);
return expression_completer (cmd, text, word);
}
ALL_BREAKPOINTS (b)
if (b->number == bnum)
{
- /* Check if this breakpoint has a Python object assigned to
- it, and if it has a definition of the "stop"
- method. This method and conditions entered into GDB from
- the CLI are mutually exclusive. */
- if (b->py_bp_object
- && gdbpy_breakpoint_has_py_cond (b->py_bp_object))
- error (_("Cannot set a condition where a Python 'stop' "
- "method has been defined in the breakpoint."));
+ /* Check if this breakpoint has a "stop" method implemented in an
+ extension language. This method and conditions entered into GDB
+ from the CLI are mutually exclusive. */
+ const struct extension_language_defn *extlang
+ = get_breakpoint_cond_ext_lang (b, EXT_LANG_NONE);
+
+ if (extlang != NULL)
+ {
+ error (_("Only one stop condition allowed. There is currently"
+ " a %s stop condition defined for this breakpoint."),
+ ext_lang_capitalized_name (extlang));
+ }
set_breakpoint_condition (b, p, from_tty);
if (is_breakpoint (b))
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
return;
}
{
if (is_tracepoint (b))
{
- /* We need to verify that each top-level element of commands is
- valid for tracepoints, that there's at most one
- while-stepping element, and that while-stepping's body has
- valid tracing commands excluding nested while-stepping. */
+ struct tracepoint *t = (struct tracepoint *) b;
struct command_line *c;
struct command_line *while_stepping = 0;
+
+ /* Reset the while-stepping step count. The previous commands
+ might have included a while-stepping action, while the new
+ ones might not. */
+ t->step_count = 0;
+
+ /* We need to verify that each top-level element of commands is
+ valid for tracepoints, that there's at most one
+ while-stepping element, and that the while-stepping's body
+ has valid tracing commands excluding nested while-stepping.
+ We also need to validate the tracepoint action line in the
+ context of the tracepoint --- validate_actionline actually
+ has side effects, like setting the tracepoint's
+ while-stepping STEP_COUNT, in addition to checking if the
+ collect/teval actions parse and make sense in the
+ tracepoint's context. */
for (c = commands; c; c = c->next)
{
if (c->control_type == while_stepping_control)
else
while_stepping = c;
}
+
+ validate_actionline (c->line, b);
}
if (while_stepping)
{
decref_counted_command_line (&b->commands);
b->commands = alloc_counted_command_line (commands);
- breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
{
struct breakpoint *b = closure;
- validate_actionline (&line, b);
+ validate_actionline (line, b);
}
/* A structure used to pass information through
incref_counted_command_line (info->cmd);
decref_counted_command_line (&b->commands);
b->commands = info->cmd;
- breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
}
return 1;
}
+/* Update BUF, which is LEN bytes read from the target address
+ MEMADDR, by replacing a memory breakpoint with its shadowed
+ contents.
+
+ If READBUF is not NULL, this buffer must not overlap with the of
+ the breakpoint location's shadow_contents buffer. Otherwise, a
+ failed assertion internal error will be raised. */
+
+static void
+one_breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
+ const gdb_byte *writebuf_org,
+ ULONGEST memaddr, LONGEST len,
+ struct bp_target_info *target_info,
+ struct gdbarch *gdbarch)
+{
+ /* Now do full processing of the found relevant range of elements. */
+ CORE_ADDR bp_addr = 0;
+ int bp_size = 0;
+ int bptoffset = 0;
+
+ if (!breakpoint_address_match (target_info->placed_address_space, 0,
+ current_program_space->aspace, 0))
+ {
+ /* The breakpoint is inserted in a different address space. */
+ return;
+ }
+
+ /* Addresses and length of the part of the breakpoint that
+ we need to copy. */
+ bp_addr = target_info->placed_address;
+ bp_size = target_info->shadow_len;
+
+ if (bp_addr + bp_size <= memaddr)
+ {
+ /* The breakpoint is entirely before the chunk of memory we are
+ reading. */
+ return;
+ }
+
+ if (bp_addr >= memaddr + len)
+ {
+ /* The breakpoint is entirely after the chunk of memory we are
+ reading. */
+ return;
+ }
+
+ /* Offset within shadow_contents. */
+ if (bp_addr < memaddr)
+ {
+ /* Only copy the second part of the breakpoint. */
+ bp_size -= memaddr - bp_addr;
+ bptoffset = memaddr - bp_addr;
+ bp_addr = memaddr;
+ }
+
+ if (bp_addr + bp_size > memaddr + len)
+ {
+ /* Only copy the first part of the breakpoint. */
+ bp_size -= (bp_addr + bp_size) - (memaddr + len);
+ }
+
+ if (readbuf != NULL)
+ {
+ /* Verify that the readbuf buffer does not overlap with the
+ shadow_contents buffer. */
+ gdb_assert (target_info->shadow_contents >= readbuf + len
+ || readbuf >= (target_info->shadow_contents
+ + target_info->shadow_len));
+
+ /* Update the read buffer with this inserted breakpoint's
+ shadow. */
+ memcpy (readbuf + bp_addr - memaddr,
+ target_info->shadow_contents + bptoffset, bp_size);
+ }
+ else
+ {
+ const unsigned char *bp;
+ CORE_ADDR addr = target_info->reqstd_address;
+ int placed_size;
+
+ /* Update the shadow with what we want to write to memory. */
+ memcpy (target_info->shadow_contents + bptoffset,
+ writebuf_org + bp_addr - memaddr, bp_size);
+
+ /* Determine appropriate breakpoint contents and size for this
+ address. */
+ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &placed_size);
+
+ /* Update the final write buffer with this inserted
+ breakpoint's INSN. */
+ memcpy (writebuf + bp_addr - memaddr, bp + bptoffset, bp_size);
+ }
+}
+
/* Update BUF, which is LEN bytes read from the target address MEMADDR,
by replacing any memory breakpoints with their shadowed contents.
/* Left boundary, right boundary and median element of our binary
search. */
unsigned bc_l, bc_r, bc;
+ size_t i;
/* Find BC_L which is a leftmost element which may affect BUF
content. It is safe to report lower value but a failure to
if (!bp_location_has_shadow (bl))
continue;
- if (!breakpoint_address_match (bl->target_info.placed_address_space, 0,
- current_program_space->aspace, 0))
- continue;
-
- /* Addresses and length of the part of the breakpoint that
- we need to copy. */
- bp_addr = bl->target_info.placed_address;
- bp_size = bl->target_info.shadow_len;
-
- if (bp_addr + bp_size <= memaddr)
- /* The breakpoint is entirely before the chunk of memory we
- are reading. */
- continue;
- if (bp_addr >= memaddr + len)
- /* The breakpoint is entirely after the chunk of memory we are
- reading. */
- continue;
+ one_breakpoint_xfer_memory (readbuf, writebuf, writebuf_org,
+ memaddr, len, &bl->target_info, bl->gdbarch);
+ }
- /* Offset within shadow_contents. */
- if (bp_addr < memaddr)
- {
- /* Only copy the second part of the breakpoint. */
- bp_size -= memaddr - bp_addr;
- bptoffset = memaddr - bp_addr;
- bp_addr = memaddr;
- }
+ /* Now process single-step breakpoints. These are not found in the
+ bp_location array. */
+ for (i = 0; i < 2; i++)
+ {
+ struct bp_target_info *bp_tgt = single_step_breakpoints[i];
- if (bp_addr + bp_size > memaddr + len)
- {
- /* Only copy the first part of the breakpoint. */
- bp_size -= (bp_addr + bp_size) - (memaddr + len);
- }
+ if (bp_tgt != NULL)
+ {
+ struct gdbarch *gdbarch = single_step_gdbarch[i];
- 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,
- bl->target_info.shadow_contents + bptoffset, bp_size);
- }
- else
- {
- struct gdbarch *gdbarch = bl->gdbarch;
- const unsigned char *bp;
- CORE_ADDR placed_address = bl->target_info.placed_address;
- unsigned placed_size = bl->target_info.placed_size;
-
- /* Update the shadow with what we want to write to memory. */
- memcpy (bl->target_info.shadow_contents + bptoffset,
- writebuf_org + bp_addr - memaddr, bp_size);
-
- /* Determine appropriate breakpoint contents and size for this
- address. */
- bp = gdbarch_breakpoint_from_pc (gdbarch, &placed_address, &placed_size);
-
- /* Update the final write buffer with this inserted
- breakpoint's INSN. */
- memcpy (writebuf + bp_addr - memaddr, bp + bptoffset, bp_size);
- }
- }
+ one_breakpoint_xfer_memory (readbuf, writebuf, writebuf_org,
+ memaddr, len, bp_tgt, gdbarch);
+ }
+ }
}
+
\f
/* Return true if BPT is either a software breakpoint or a hardware
b->disposition = disp_del_at_next_stop;
}
+/* Extract a bitfield value from value VAL using the bit parameters contained in
+ watchpoint W. */
+
+static struct value *
+extract_bitfield_from_watchpoint_value (struct watchpoint *w, struct value *val)
+{
+ struct value *bit_val;
+
+ if (val == NULL)
+ return NULL;
+
+ bit_val = allocate_value (value_type (val));
+
+ unpack_value_bitfield (bit_val,
+ w->val_bitpos,
+ w->val_bitsize,
+ value_contents_for_printing (val),
+ value_offset (val),
+ val);
+
+ return bit_val;
+}
+
/* Assuming that B is a watchpoint:
- Reparse watchpoint expression, if REPARSE is non-zero
- Evaluate expression and store the result in B->val
if (within_current_scope && reparse)
{
- char *s;
+ const char *s;
if (b->exp)
{
don't try to insert watchpoint. We don't automatically delete
such watchpoint, though, since failure to parse expression
is different from out-of-scope watchpoint. */
- if ( !target_has_execution)
+ if (!target_has_execution)
{
/* Without execution, memory can't change. No use to try and
set watchpoint locations. The watchpoint will be reset when
the target gains execution, through breakpoint_re_set. */
+ if (!can_use_hw_watchpoints)
+ {
+ if (b->base.ops->works_in_software_mode (&b->base))
+ b->base.type = bp_watchpoint;
+ else
+ error (_("Can't set read/access watchpoint when "
+ "hardware watchpoints are disabled."));
+ }
}
else if (within_current_scope && b->exp)
{
struct value *val_chain, *v, *result, *next;
struct program_space *frame_pspace;
- fetch_subexp_value (b->exp, &pc, &v, &result, &val_chain);
+ fetch_subexp_value (b->exp, &pc, &v, &result, &val_chain, 0);
/* Avoid setting b->val if it's already set. The meaning of
b->val is 'the last value' user saw, and we should update
watchpoints. */
if (!b->val_valid && !is_masked_watchpoint (&b->base))
{
+ if (b->val_bitsize != 0)
+ {
+ v = extract_bitfield_from_watchpoint_value (b, v);
+ if (v != NULL)
+ release_value (v);
+ }
b->val = v;
b->val_valid = 1;
}
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR addr;
- int len, type;
+ int type;
struct bp_location *loc, **tmp;
+ int bitpos = 0, bitsize = 0;
+
+ if (value_bitsize (v) != 0)
+ {
+ /* Extract the bit parameters out from the bitfield
+ sub-expression. */
+ bitpos = value_bitpos (v);
+ bitsize = value_bitsize (v);
+ }
+ else if (v == result && b->val_bitsize != 0)
+ {
+ /* If VAL_BITSIZE != 0 then RESULT is actually a bitfield
+ lvalue whose bit parameters are saved in the fields
+ VAL_BITPOS and VAL_BITSIZE. */
+ bitpos = b->val_bitpos;
+ bitsize = b->val_bitsize;
+ }
addr = value_address (v);
- len = TYPE_LENGTH (value_type (v));
+ if (bitsize != 0)
+ {
+ /* Skip the bytes that don't contain the bitfield. */
+ addr += bitpos / 8;
+ }
+
type = hw_write;
if (b->base.type == bp_read_watchpoint)
type = hw_read;
loc->pspace = frame_pspace;
loc->address = addr;
- loc->length = len;
+
+ if (bitsize != 0)
+ {
+ /* Just cover the bytes that make up the bitfield. */
+ loc->length = ((bitpos % 8) + bitsize + 7) / 8;
+ }
+ else
+ loc->length = TYPE_LENGTH (value_type (v));
+
loc->watchpoint_type = type;
}
}
}
}
else if (!b->base.ops->works_in_software_mode (&b->base))
- error (_("Expression cannot be implemented with "
- "read/access watchpoint."));
+ {
+ if (!can_use_hw_watchpoints)
+ error (_("Can't set read/access watchpoint when "
+ "hardware watchpoints are disabled."));
+ else
+ error (_("Expression cannot be implemented with "
+ "read/access watchpoint."));
+ }
else
b->base.type = bp_watchpoint;
if (bl->pspace->breakpoints_not_allowed)
return 0;
+ /* Don't insert a breakpoint if we're trying to step past its
+ location. */
+ if ((bl->loc_type == bp_loc_software_breakpoint
+ || bl->loc_type == bp_loc_hardware_breakpoint)
+ && stepping_past_instruction_at (bl->pspace->aspace,
+ bl->address))
+ {
+ if (debug_infrun)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: skipping breakpoint: "
+ "stepping past insn at: %s\n",
+ paddress (bl->gdbarch, bl->address));
+ }
+ return 0;
+ }
+
return 1;
}
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)
int modified = bl->needs_update;
struct bp_location *loc;
+ /* Release conditions left over from a previous insert. */
+ VEC_free (agent_expr_p, bl->target_info.conditions);
+
/* This is only meaningful if the target is
evaluating conditions and if the user has
opted for condition evaluation on the target's
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;
+ volatile struct gdb_exception ex;
+ const char *cmdrest;
+ const 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_const (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_const (cmdrest);
+
+ if (!(*cmdrest == ',' || *cmdrest == '\0'))
+ error (_("Invalid argument syntax"));
+
+ if (*cmdrest == ',')
+ cmdrest++;
+ cmdrest = skip_spaces_const (cmdrest);
+
+ /* For each argument, make an expression. */
+
+ argvec = (struct expression **) alloca (strlen (cmd)
+ * sizeof (struct expression *));
+
+ nargs = 0;
+ while (*cmdrest != '\0')
+ {
+ const 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);
+ }
+
+ do_cleanups (old_cleanups);
+
+ 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;
+ }
+
+ /* 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;
+
+ /* Release commands left over from a previous insert. */
+ VEC_free (agent_expr_p, bl->target_info.tcommands);
+
+ if (!target_can_run_breakpoint_commands ())
+ return;
+
+ /* For now, limit to agent-style dprintf breakpoints. */
+ if (dprintf_style != dprintf_style_agent)
+ return;
+
+ /* For now, if we have any duplicate location that isn't a dprintf,
+ don't install the target-side commands, as that would make the
+ breakpoint not be reported to the core, and we'd lose
+ control. */
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+ {
+ loc = (*loc2p);
+ if (is_breakpoint (loc->owner)
+ && loc->pspace->num == bl->pspace->num
+ && loc->owner->type != bp_dprintf)
+ 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->cmd_bytecode == NULL)
+ return;
+
+ free_agent_expr (loc->cmd_bytecode);
+ loc->cmd_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;
+ enum errors bp_err = GDB_NO_ERROR;
+ const char *bp_err_message = NULL;
+ volatile struct gdb_exception e;
if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
return 0;
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.reqstd_address = bl->address;
bl->target_info.placed_address_space = bl->pspace->aspace;
bl->target_info.length = bl->length;
if (is_breakpoint (bl->owner))
{
build_target_condition_list (bl);
- /* Reset the condition modification marker. */
+ build_target_command_list (bl);
+ /* Reset the modification marker. */
bl->needs_update = 0;
}
program, but it's not going to work anyway with current
gdb. */
struct mem_region *mr
- = lookup_mem_region (bl->target_info.placed_address);
+ = lookup_mem_region (bl->target_info.reqstd_address);
if (mr)
{
}
}
else if (bl->loc_type == bp_loc_software_breakpoint
- && mr->attrib.mode != MEM_RW)
- warning (_("cannot set software breakpoint "
- "at readonly address %s"),
- paddress (bl->gdbarch, bl->address));
+ && mr->attrib.mode != MEM_RW)
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ _("Cannot insert breakpoint %d.\n"
+ "Cannot set software breakpoint "
+ "at read-only address %s\n"),
+ bl->owner->number,
+ paddress (bl->gdbarch, bl->address));
+ return 1;
+ }
}
}
|| !(section_is_overlay (bl->section)))
{
/* No overlay handling: just set the breakpoint. */
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ int val;
- val = bl->owner->ops->insert_location (bl);
+ val = bl->owner->ops->insert_location (bl);
+ if (val)
+ bp_err = GENERIC_ERROR;
+ }
+ if (e.reason < 0)
+ {
+ bp_err = e.error;
+ bp_err_message = e.message;
+ }
}
else
{
bl->section);
/* Set a software (trap) breakpoint at the LMA. */
bl->overlay_target_info = bl->target_info;
- bl->overlay_target_info.placed_address = addr;
- val = target_insert_breakpoint (bl->gdbarch,
- &bl->overlay_target_info);
- if (val != 0)
+ bl->overlay_target_info.reqstd_address = addr;
+
+ /* No overlay handling: just set the breakpoint. */
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ int val;
+
+ val = target_insert_breakpoint (bl->gdbarch,
+ &bl->overlay_target_info);
+ if (val)
+ bp_err = GENERIC_ERROR;
+ }
+ if (e.reason < 0)
+ {
+ bp_err = e.error;
+ bp_err_message = e.message;
+ }
+
+ if (bp_err != GDB_NO_ERROR)
fprintf_unfiltered (tmp_error_stream,
"Overlay breakpoint %d "
"failed: in ROM?\n",
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)
+ {
+ int val;
+
+ val = bl->owner->ops->insert_location (bl);
+ if (val)
+ bp_err = GENERIC_ERROR;
+ }
+ if (e.reason < 0)
+ {
+ bp_err = e.error;
+ bp_err_message = e.message;
+ }
}
else
{
}
}
- if (val)
+ if (bp_err != GDB_NO_ERROR)
{
/* Can't set the breakpoint. */
- if (solib_name_from_address (bl->pspace, bl->address))
+
+ /* In some cases, we might not be able to insert a
+ breakpoint in a shared library that has already been
+ removed, but we have not yet processed the shlib unload
+ event. Unfortunately, some targets that implement
+ breakpoint insertion themselves can't tell why the
+ breakpoint insertion failed (e.g., the remote target
+ doesn't define error codes), so we must treat generic
+ errors as memory errors. */
+ if ((bp_err == GENERIC_ERROR || bp_err == MEMORY_ERROR)
+ && bl->loc_type == bp_loc_software_breakpoint
+ && (solib_name_from_address (bl->pspace, bl->address)
+ || shared_objfile_contains_address_p (bl->pspace,
+ bl->address)))
{
/* See also: disable_breakpoints_in_shlibs. */
- val = 0;
bl->shlib_disabled = 1;
observer_notify_breakpoint_modified (bl->owner);
if (!*disabled_breaks)
*disabled_breaks = 1;
fprintf_unfiltered (tmp_error_stream,
"breakpoint #%d\n", bl->owner->number);
+ return 0;
}
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_bp_error_explained_already = bp_err_message != NULL;
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert hardware breakpoint %d%s",
+ bl->owner->number, bp_err_message ? ":" : ".\n");
+ if (bp_err_message != NULL)
+ fprintf_unfiltered (tmp_error_stream, "%s.\n", bp_err_message);
}
else
{
- fprintf_unfiltered (tmp_error_stream,
- "Cannot insert breakpoint %d.\n",
- bl->owner->number);
- fprintf_filtered (tmp_error_stream,
- "Error accessing memory address ");
- fputs_filtered (paddress (bl->gdbarch, bl->address),
- tmp_error_stream);
- fprintf_filtered (tmp_error_stream, ": %s.\n",
- safe_strerror (val));
+ if (bp_err_message == NULL)
+ {
+ char *message
+ = memory_error_message (TARGET_XFER_E_IO,
+ bl->gdbarch, bl->address);
+ struct cleanup *old_chain = make_cleanup (xfree, message);
+
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert breakpoint %d.\n"
+ "%s\n",
+ bl->owner->number, message);
+ do_cleanups (old_chain);
+ }
+ else
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert breakpoint %d: %s\n",
+ bl->owner->number,
+ bp_err_message);
+ }
}
+ return 1;
}
}
else
bl->inserted = 1;
- return val;
+ return 0;
}
else if (bl->loc_type == bp_loc_hardware_watchpoint
watchpoints. It's not clear that it's necessary... */
&& bl->owner->disposition != disp_del_at_next_stop)
{
+ int val;
+
gdb_assert (bl->owner->ops != NULL
&& bl->owner->ops->insert_location != NULL);
else if (bl->owner->type == bp_catchpoint)
{
+ int val;
+
gdb_assert (bl->owner->ops != NULL
&& bl->owner->ops->insert_location != NULL);
/* Now update the global location list to permanently delete the
removed locations above. */
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
}
/* Make sure all breakpoints are inserted in inferior.
update_watchpoint (w, 0 /* don't reparse. */);
}
- update_global_location_list (1);
-
- /* update_global_location_list does not insert breakpoints when
- always_inserted_mode is not enabled. Explicitly insert them
- now. */
- if (!breakpoints_always_inserted_mode ())
- insert_breakpoint_locations ();
+ /* Updating watchpoints creates new locations, so update the global
+ location list. Explicitly tell ugll to insert locations and
+ ignore breakpoints_always_inserted_mode. */
+ update_global_location_list (UGLL_INSERT);
}
/* Invoke CALLBACK for each of bp_location. */
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);
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_details_reported);
if (val)
error_flag = val;
}
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);
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\
return val;
}
+/* When a thread exits, remove breakpoints that are related to
+ that thread. */
+
+static void
+remove_threaded_breakpoints (struct thread_info *tp, int silent)
+{
+ struct breakpoint *b, *b_tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, b_tmp)
+ {
+ if (b->thread == tp->num && user_breakpoint_p (b))
+ {
+ b->disposition = disp_del_at_next_stop;
+
+ printf_filtered (_("\
+Thread-specific breakpoint %d deleted - thread %d no longer in the thread list.\n"),
+ b->number, tp->num);
+
+ /* Hide it from the user. */
+ b->number = 0;
+ }
+ }
+}
+
/* Remove breakpoints of process PID. */
int
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);
struct breakpoint_objfile_data
{
/* Minimal symbol for "_ovly_debug_event" (if any). */
- struct minimal_symbol *overlay_msym;
+ struct bound_minimal_symbol overlay_msym;
/* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
- struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
+ struct bound_minimal_symbol longjmp_msym[NUM_LONGJMP_NAMES];
/* True if we have looked for longjmp probes. */
int longjmp_searched;
VEC (probe_p) *longjmp_probes;
/* Minimal symbol for "std::terminate()" (if any). */
- struct minimal_symbol *terminate_msym;
+ struct bound_minimal_symbol terminate_msym;
/* Minimal symbol for "_Unwind_DebugHook" (if any). */
- struct minimal_symbol *exception_msym;
+ struct bound_minimal_symbol exception_msym;
/* True if we have looked for exception probes. */
int exception_searched;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
- if (msym_not_found_p (bp_objfile_data->overlay_msym))
+ if (msym_not_found_p (bp_objfile_data->overlay_msym.minsym))
continue;
- if (bp_objfile_data->overlay_msym == NULL)
+ if (bp_objfile_data->overlay_msym.minsym == NULL)
{
- struct minimal_symbol *m;
+ struct bound_minimal_symbol m;
m = lookup_minimal_symbol_text (func_name, objfile);
- if (m == NULL)
+ if (m.minsym == NULL)
{
/* Avoid future lookups in this objfile. */
- bp_objfile_data->overlay_msym = &msym_not_found;
+ bp_objfile_data->overlay_msym.minsym = &msym_not_found;
continue;
}
bp_objfile_data->overlay_msym = m;
}
- addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->overlay_msym);
+ addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->overlay_msym);
b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
bp_overlay_event,
&internal_breakpoint_ops);
overlay_events_enabled = 0;
}
}
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
static void
struct breakpoint_objfile_data *bp_objfile_data;
gdbarch = get_objfile_arch (objfile);
- if (!gdbarch_get_longjmp_target_p (gdbarch))
- continue;
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");
+ VEC (probe_p) *ret;
+
+ ret = find_probes_in_objfile (objfile, "libc", "longjmp");
+ if (ret != NULL)
+ {
+ /* We are only interested in checking one element. */
+ struct probe *p = VEC_index (probe_p, ret, 0);
+
+ if (!can_evaluate_probe_arguments (p))
+ {
+ /* We cannot use the probe interface here, because it does
+ not know how to evaluate arguments. */
+ VEC_free (probe_p, ret);
+ ret = NULL;
+ }
+ }
+ bp_objfile_data->longjmp_probes = ret;
bp_objfile_data->longjmp_searched = 1;
}
{
struct breakpoint *b;
- b = create_internal_breakpoint (gdbarch, probe->address,
+ b = create_internal_breakpoint (gdbarch,
+ get_probe_address (probe,
+ objfile),
bp_longjmp_master,
&internal_breakpoint_ops);
b->addr_string = xstrdup ("-probe-stap libc:longjmp");
continue;
}
+ if (!gdbarch_get_longjmp_target_p (gdbarch))
+ continue;
+
for (i = 0; i < NUM_LONGJMP_NAMES; i++)
{
struct breakpoint *b;
const char *func_name;
CORE_ADDR addr;
- if (msym_not_found_p (bp_objfile_data->longjmp_msym[i]))
+ if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
continue;
func_name = longjmp_names[i];
- if (bp_objfile_data->longjmp_msym[i] == NULL)
+ if (bp_objfile_data->longjmp_msym[i].minsym == NULL)
{
- struct minimal_symbol *m;
+ struct bound_minimal_symbol m;
m = lookup_minimal_symbol_text (func_name, objfile);
- if (m == NULL)
+ if (m.minsym == NULL)
{
/* Prevent future lookups in this objfile. */
- bp_objfile_data->longjmp_msym[i] = &msym_not_found;
+ bp_objfile_data->longjmp_msym[i].minsym = &msym_not_found;
continue;
}
bp_objfile_data->longjmp_msym[i] = m;
}
- addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
+ addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
&internal_breakpoint_ops);
b->addr_string = xstrdup (func_name);
}
}
}
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
do_cleanups (old_chain);
}
bp_objfile_data = get_breakpoint_objfile_data (objfile);
- if (msym_not_found_p (bp_objfile_data->terminate_msym))
+ if (msym_not_found_p (bp_objfile_data->terminate_msym.minsym))
continue;
- if (bp_objfile_data->terminate_msym == NULL)
+ if (bp_objfile_data->terminate_msym.minsym == NULL)
{
- struct minimal_symbol *m;
+ struct bound_minimal_symbol m;
m = lookup_minimal_symbol (func_name, NULL, objfile);
- if (m == NULL || (MSYMBOL_TYPE (m) != mst_text
- && MSYMBOL_TYPE (m) != mst_file_text))
+ if (m.minsym == NULL || (MSYMBOL_TYPE (m.minsym) != mst_text
+ && MSYMBOL_TYPE (m.minsym) != mst_file_text))
{
/* Prevent future lookups in this objfile. */
- bp_objfile_data->terminate_msym = &msym_not_found;
+ bp_objfile_data->terminate_msym.minsym = &msym_not_found;
continue;
}
bp_objfile_data->terminate_msym = m;
}
- addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->terminate_msym);
+ addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->terminate_msym);
b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
bp_std_terminate_master,
&internal_breakpoint_ops);
}
}
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
do_cleanups (old_chain);
}
/* 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");
+ VEC (probe_p) *ret;
+
+ ret = find_probes_in_objfile (objfile, "libgcc", "unwind");
+
+ if (ret != NULL)
+ {
+ /* We are only interested in checking one element. */
+ struct probe *p = VEC_index (probe_p, ret, 0);
+
+ if (!can_evaluate_probe_arguments (p))
+ {
+ /* We cannot use the probe interface here, because it does
+ not know how to evaluate arguments. */
+ VEC_free (probe_p, ret);
+ ret = NULL;
+ }
+ }
+ bp_objfile_data->exception_probes = ret;
bp_objfile_data->exception_searched = 1;
}
{
struct breakpoint *b;
- b = create_internal_breakpoint (gdbarch, probe->address,
+ b = create_internal_breakpoint (gdbarch,
+ get_probe_address (probe,
+ objfile),
bp_exception_master,
&internal_breakpoint_ops);
b->addr_string = xstrdup ("-probe-stap libgcc:unwind");
/* Otherwise, try the hook function. */
- if (msym_not_found_p (bp_objfile_data->exception_msym))
+ if (msym_not_found_p (bp_objfile_data->exception_msym.minsym))
continue;
gdbarch = get_objfile_arch (objfile);
- if (bp_objfile_data->exception_msym == NULL)
+ if (bp_objfile_data->exception_msym.minsym == NULL)
{
- struct minimal_symbol *debug_hook;
+ struct bound_minimal_symbol debug_hook;
debug_hook = lookup_minimal_symbol (func_name, NULL, objfile);
- if (debug_hook == NULL)
+ if (debug_hook.minsym == NULL)
{
- bp_objfile_data->exception_msym = &msym_not_found;
+ bp_objfile_data->exception_msym.minsym = &msym_not_found;
continue;
}
bp_objfile_data->exception_msym = debug_hook;
}
- addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
+ addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
¤t_target);
b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
b->enable_state = bp_disabled;
}
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
void
continue;
}
}
- /* FIXME what about longjmp breakpoints? Re-create them here? */
- create_overlay_event_breakpoint ();
- create_longjmp_master_breakpoint ();
- create_std_terminate_master_breakpoint ();
- create_exception_master_breakpoint ();
}
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 (ptid_get_pid (ptid) == ptid_get_pid (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)
continue;
+ /* This function must physically remove breakpoints locations
+ from the specified ptid, without modifying the breakpoint
+ package's state. Locations of type bp_loc_other are only
+ maintained at GDB side. So, there is no need to remove
+ these bp_loc_other locations. Moreover, removing these
+ would modify the breakpoint package's state. */
+ if (bl->loc_type == bp_loc_other)
+ continue;
+
if (bl->inserted)
val |= remove_breakpoint_1 (bl, mark_inserted);
}
|| !(section_is_overlay (bl->section)))
{
/* No overlay handling: just remove the breakpoint. */
- val = bl->owner->ops->remove_location (bl);
+
+ /* If we're trying to uninsert a memory breakpoint that we
+ know is set in a dynamic object that is marked
+ shlib_disabled, then either the dynamic object was
+ removed with "remove-symbol-file" or with
+ "nosharedlibrary". In the former case, we don't know
+ whether another dynamic object might have loaded over the
+ breakpoint's address -- the user might well let us know
+ about it next with add-symbol-file (the whole point of
+ add-symbol-file is letting the user manually maintain a
+ list of dynamically loaded objects). If we have the
+ breakpoint's shadow memory, that is, this is a software
+ breakpoint managed by GDB, check whether the breakpoint
+ is still inserted in memory, to avoid overwriting wrong
+ code with stale saved shadow contents. Note that HW
+ breakpoints don't have shadow memory, as they're
+ implemented using a mechanism that is not dependent on
+ being able to modify the target's memory, and as such
+ they should always be removed. */
+ if (bl->shlib_disabled
+ && bl->target_info.shadow_len != 0
+ && !memory_validate_breakpoint (bl->gdbarch, &bl->target_info))
+ val = 0;
+ else
+ val = bl->owner->ops->remove_location (bl);
}
else
{
}
}
- /* In some cases, we might not be able to remove a breakpoint
- in a shared library that has already been removed, but we
- have not yet processed the shlib unload event. */
- if (val && solib_name_from_address (bl->pspace, bl->address))
+ /* In some cases, we might not be able to remove a breakpoint in
+ a shared library that has already been removed, but we have
+ not yet processed the shlib unload event. Similarly for an
+ unloaded add-symbol-file object - the user might not yet have
+ had the chance to remove-symbol-file it. shlib_disabled will
+ be set if the library/object has already been removed, but
+ the breakpoint hasn't been uninserted yet, e.g., after
+ "nosharedlibrary" or "remove-symbol-file" with breakpoints
+ always-inserted mode. */
+ if (val
+ && (bl->loc_type == bp_loc_software_breakpoint
+ && (bl->shlib_disabled
+ || solib_name_from_address (bl->pspace, bl->address)
+ || shared_objfile_contains_address_p (bl->pspace,
+ bl->address))))
val = 0;
if (val)
/* 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)
return 0;
}
-/* This function returns non-zero iff there is a software breakpoint
- inserted at PC. */
+/* Ignoring deprecated raw breakpoints, return non-zero iff there is a
+ software breakpoint inserted at PC. */
-int
-software_breakpoint_inserted_here_p (struct address_space *aspace,
- CORE_ADDR pc)
+static struct bp_location *
+find_non_raw_software_breakpoint_inserted_here (struct address_space *aspace,
+ CORE_ADDR pc)
{
struct bp_location *bl, **blp_tmp;
&& !section_is_mapped (bl->section))
continue; /* unmapped overlay -- can't be a match */
else
- return 1;
+ return bl;
}
}
+ return NULL;
+}
+
+/* This function returns non-zero iff there is a software breakpoint
+ inserted at PC. */
+
+int
+software_breakpoint_inserted_here_p (struct address_space *aspace,
+ CORE_ADDR pc)
+{
+ if (find_non_raw_software_breakpoint_inserted_here (aspace, pc) != NULL)
+ return 1;
+
/* Also check for software single-step breakpoints. */
if (single_step_breakpoint_inserted_here_p (aspace, pc))
return 1;
return NULL;
}
+/* See breakpoint.h. */
+
+int
+bpstat_explains_signal (bpstat bsp, enum gdb_signal sig)
+{
+ for (; bsp != NULL; bsp = bsp->next)
+ {
+ if (bsp->breakpoint_at == NULL)
+ {
+ /* A moribund location can never explain a signal other than
+ GDB_SIGNAL_TRAP. */
+ if (sig == GDB_SIGNAL_TRAP)
+ return 1;
+ }
+ else
+ {
+ if (bsp->breakpoint_at->ops->explains_signal (bsp->breakpoint_at,
+ sig))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* 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
return PRINT_UNKNOWN;
}
-/* Evaluate the expression EXP and return 1 if value is zero. This is
- used inside a catch_errors to evaluate the breakpoint condition.
+/* Evaluate the expression EXP and return 1 if value is zero.
+ This returns the inverse of the condition because it is called
+ from catch_errors which returns 0 if an exception happened, and if an
+ exception happens we want execution to stop.
The argument is a "struct expression *" that has been cast to a
- "char *" to make it pass through catch_errors. */
+ "void *" to make it pass through catch_errors. */
static int
breakpoint_cond_eval (void *exp)
w->watchpoint_triggered = watch_triggered_unknown;
}
- return stopped_by_watchpoint;
+ return 1;
}
/* The target could report the data address. Mark watchpoints
return WP_VALUE_CHANGED;
mark = value_mark ();
- fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
+ fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL, 0);
+
+ if (b->val_bitsize != 0)
+ new_val = extract_bitfield_from_watchpoint_value (b, new_val);
/* We use value_equal_contents instead of value_equal because
the latter coerces an array to a pointer, thus comparing just
}
}
-
-/* Check conditions (condition proper, frame, thread and ignore count)
+/* For breakpoints that are currently marked as telling gdb to stop,
+ check conditions (condition proper, frame, thread and ignore count)
of breakpoint referred to by BS. If we should not stop for this
breakpoint, set BS->stop to 0. */
static void
bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
{
- int thread_id = pid_to_thread_id (ptid);
const struct bp_location *bl;
struct breakpoint *b;
+ int value_is_zero = 0;
+ struct expression *cond;
+
+ gdb_assert (bs->stop);
/* BS is built for existing struct breakpoint. */
bl = bs->bp_location_at;
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 (bs->stop)
{
- int value_is_zero = 0;
- struct expression *cond;
+ bs->stop = 0;
+ return;
+ }
- /* Evaluate Python breakpoints that have a "stop"
- method implemented. */
- if (b->py_bp_object)
- bs->stop = gdbpy_should_stop (b->py_bp_object);
+ /* If this is a thread/task-specific breakpoint, don't waste cpu
+ evaluating the condition if this isn't the specified
+ thread/task. */
+ if ((b->thread != -1 && b->thread != pid_to_thread_id (ptid))
+ || (b->task != 0 && b->task != ada_get_task_number (ptid)))
- if (is_watchpoint (b))
- {
- struct watchpoint *w = (struct watchpoint *) b;
+ {
+ bs->stop = 0;
+ return;
+ }
- cond = w->cond_exp;
- }
- else
- cond = bl->cond;
+ /* Evaluate extension language breakpoints that have a "stop" method
+ implemented. */
+ bs->stop = breakpoint_ext_lang_cond_says_stop (b);
- if (cond && b->disposition != disp_del_at_next_stop)
- {
- int within_current_scope = 1;
- struct watchpoint * w;
+ if (is_watchpoint (b))
+ {
+ struct watchpoint *w = (struct watchpoint *) b;
- /* We use value_mark and value_free_to_mark because it could
- be a long time before we return to the command level and
- call free_all_values. We can't call free_all_values
- because we might be in the middle of evaluating a
- function call. */
- struct value *mark = value_mark ();
+ cond = w->cond_exp;
+ }
+ else
+ cond = bl->cond;
- if (is_watchpoint (b))
- w = (struct watchpoint *) b;
- else
- w = NULL;
-
- /* Need to select the frame, with all that implies so that
- the conditions will have the right context. Because we
- use the frame, we will not see an inlined function's
- variables when we arrive at a breakpoint at the start
- of the inlined function; the current frame will be the
- call site. */
- if (w == NULL || w->cond_exp_valid_block == NULL)
- select_frame (get_current_frame ());
- else
- {
- struct frame_info *frame;
-
- /* For local watchpoint expressions, which particular
- instance of a local is being watched matters, so we
- keep track of the frame to evaluate the expression
- in. To evaluate the condition however, it doesn't
- really matter which instantiation of the function
- where the condition makes sense triggers the
- watchpoint. This allows an expression like "watch
- global if q > 10" set in `func', catch writes to
- global on all threads that call `func', or catch
- writes on all recursive calls of `func' by a single
- thread. We simply always evaluate the condition in
- the innermost frame that's executing where it makes
- sense to evaluate the condition. It seems
- intuitive. */
- frame = block_innermost_frame (w->cond_exp_valid_block);
- if (frame != NULL)
- select_frame (frame);
- else
- within_current_scope = 0;
- }
- if (within_current_scope)
- value_is_zero
- = catch_errors (breakpoint_cond_eval, cond,
- "Error in testing breakpoint condition:\n",
- RETURN_MASK_ALL);
- else
- {
- warning (_("Watchpoint condition cannot be tested "
- "in the current scope"));
- /* If we failed to set the right context for this
- watchpoint, unconditionally report it. */
- value_is_zero = 0;
- }
- /* FIXME-someday, should give breakpoint #. */
- value_free_to_mark (mark);
- }
+ if (cond && b->disposition != disp_del_at_next_stop)
+ {
+ int within_current_scope = 1;
+ struct watchpoint * w;
- if (cond && value_is_zero)
+ /* We use value_mark and value_free_to_mark because it could
+ be a long time before we return to the command level and
+ call free_all_values. We can't call free_all_values
+ because we might be in the middle of evaluating a
+ function call. */
+ struct value *mark = value_mark ();
+
+ if (is_watchpoint (b))
+ w = (struct watchpoint *) b;
+ else
+ w = NULL;
+
+ /* Need to select the frame, with all that implies so that
+ the conditions will have the right context. Because we
+ use the frame, we will not see an inlined function's
+ variables when we arrive at a breakpoint at the start
+ of the inlined function; the current frame will be the
+ call site. */
+ if (w == NULL || w->cond_exp_valid_block == NULL)
+ select_frame (get_current_frame ());
+ else
{
- bs->stop = 0;
+ struct frame_info *frame;
+
+ /* For local watchpoint expressions, which particular
+ instance of a local is being watched matters, so we
+ keep track of the frame to evaluate the expression
+ in. To evaluate the condition however, it doesn't
+ really matter which instantiation of the function
+ where the condition makes sense triggers the
+ watchpoint. This allows an expression like "watch
+ global if q > 10" set in `func', catch writes to
+ global on all threads that call `func', or catch
+ writes on all recursive calls of `func' by a single
+ thread. We simply always evaluate the condition in
+ the innermost frame that's executing where it makes
+ sense to evaluate the condition. It seems
+ intuitive. */
+ frame = block_innermost_frame (w->cond_exp_valid_block);
+ if (frame != NULL)
+ select_frame (frame);
+ else
+ within_current_scope = 0;
}
- else if (b->thread != -1 && b->thread != thread_id)
+ if (within_current_scope)
+ value_is_zero
+ = catch_errors (breakpoint_cond_eval, cond,
+ "Error in testing breakpoint condition:\n",
+ RETURN_MASK_ALL);
+ else
{
- bs->stop = 0;
+ warning (_("Watchpoint condition cannot be tested "
+ "in the current scope"));
+ /* If we failed to set the right context for this
+ watchpoint, unconditionally report it. */
+ value_is_zero = 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);
- observer_notify_breakpoint_modified (b);
- }
+ /* FIXME-someday, should give breakpoint #. */
+ value_free_to_mark (mark);
+ }
+
+ if (cond && value_is_zero)
+ {
+ bs->stop = 0;
}
+ else if (b->ignore_count > 0)
+ {
+ b->ignore_count--;
+ bs->stop = 0;
+ /* Increase the hit count even though we don't stop. */
+ ++(b->hit_count);
+ observer_notify_breakpoint_modified (b);
+ }
}
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))
if (command_line_is_silent (bs->commands
? bs->commands->commands : NULL))
bs->print = 0;
+
+ b->ops->after_condition_true (bs);
}
}
}
if (need_remove_insert)
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
else if (removed_any)
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
return bs_head;
}
target_terminal_inferior ();
}
-/* Handle an solib event by calling solib_add. */
-
-void
-handle_solib_event (void)
-{
- clear_program_space_solib_cache (current_inferior ()->pspace);
-
- /* Check for any newly added shared libraries if we're supposed to
- be adding them automatically. Switch terminal for any messages
- produced by breakpoint_re_set. */
- target_terminal_ours_for_output ();
-#ifdef SOLIB_ADD
- SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
-#else
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
-#endif
- target_terminal_inferior ();
-}
-
/* Prepare WHAT final decision for infrun. */
/* Decide what infrun needs to do with this bpstat. */
break;
case bp_dprintf:
- this_action = BPSTAT_WHAT_STOP_SILENT;
+ if (bs->stop)
+ this_action = BPSTAT_WHAT_STOP_SILENT;
+ else
+ this_action = BPSTAT_WHAT_SINGLE;
break;
default:
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);
}
return bptypes[(int) type].description;
}
+/* 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;
+ 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;
+
+ back_to = make_cleanup_ui_out_list_begin_end (uiout, field_name);
+
+ 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));
+ }
+ }
+
+ do_cleanups (back_to);
+}
+
/* Print B to gdb_stdout. */
static void
}
- /* 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)
ui_out_text (uiout, "\n");
}
- if (!part_of_multiple && b->hit_count)
+ if (!part_of_multiple)
{
- /* 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");
+ 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)
&& loc1->length == loc2->length);
}
-/* Returns true if {ASPACE1,ADDR1} and {ASPACE2,ADDR2} represent the
- same breakpoint location. In most targets, this can only be true
- if ASPACE1 matches ASPACE2. On targets that have global
- breakpoints, the address space doesn't really matter. */
+/* See breakpoint.h. */
-static int
+int
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);
}
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
/* longjmp_breakpoint_ops ensures INITIATING_FRAME is cleared again
after their removal. */
clone = momentary_breakpoint_from_master (b, type,
- &longjmp_breakpoint_ops);
+ &longjmp_breakpoint_ops, 1);
clone->thread = thread;
}
struct breakpoint *new_b;
new_b = momentary_breakpoint_from_master (b, bp_longjmp_call_dummy,
- &momentary_breakpoint_ops);
+ &momentary_breakpoint_ops,
+ 1);
new_b->thread = pid_to_thread_id (inferior_ptid);
/* Link NEW_B into the chain of RETVAL breakpoints. */
}
/* Verify all existing dummy frames and their associated breakpoints for
- THREAD. Remove those which can no longer be found in the current frame
+ TP. 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
frames. */
void
-check_longjmp_breakpoint_for_call_dummy (int thread)
+check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp)
{
struct breakpoint *b, *b_tmp;
ALL_BREAKPOINTS_SAFE (b, b_tmp)
- if (b->type == bp_longjmp_call_dummy && b->thread == thread)
+ if (b->type == bp_longjmp_call_dummy && b->thread == tp->num)
{
struct breakpoint *dummy_b = b->related_breakpoint;
|| frame_find_by_id (dummy_b->frame_id) != NULL)
continue;
- dummy_frame_discard (dummy_b->frame_id);
+ dummy_frame_discard (dummy_b->frame_id, tp->ptid);
while (b->related_breakpoint != b)
{
if (b->type == bp_overlay_event)
{
b->enable_state = bp_enabled;
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
overlay_events_enabled = 1;
}
}
if (b->type == bp_overlay_event)
{
b->enable_state = bp_disabled;
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
overlay_events_enabled = 0;
}
}
&& b->type == bp_std_terminate_master)
{
momentary_breakpoint_from_master (b, bp_std_terminate,
- &momentary_breakpoint_ops);
+ &momentary_breakpoint_ops, 1);
}
}
b->addr_string
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
- update_global_location_list_nothrow (1);
+ update_global_location_list_nothrow (UGLL_MAY_INSERT);
return b;
}
b = create_internal_breakpoint (gdbarch, address, bp_jit_event,
&internal_breakpoint_ops);
- update_global_location_list_nothrow (1);
+ update_global_location_list_nothrow (UGLL_MAY_INSERT);
return b;
}
delete_breakpoint (b);
}
-struct breakpoint *
-create_solib_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
+/* See breakpoint.h. */
+
+void
+remove_solib_event_breakpoints_at_next_stop (void)
+{
+ struct breakpoint *b, *b_tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, b_tmp)
+ if (b->type == bp_shlib_event
+ && b->loc->pspace == current_program_space)
+ b->disposition = disp_del_at_next_stop;
+}
+
+/* Helper for create_solib_event_breakpoint /
+ create_and_insert_solib_event_breakpoint. Allows specifying which
+ INSERT_MODE to pass through to update_global_location_list. */
+
+static struct breakpoint *
+create_solib_event_breakpoint_1 (struct gdbarch *gdbarch, CORE_ADDR address,
+ enum ugll_insert_mode insert_mode)
{
struct breakpoint *b;
b = create_internal_breakpoint (gdbarch, address, bp_shlib_event,
&internal_breakpoint_ops);
- update_global_location_list_nothrow (1);
+ update_global_location_list_nothrow (insert_mode);
+ return b;
+}
+
+struct breakpoint *
+create_solib_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+ return create_solib_event_breakpoint_1 (gdbarch, address, UGLL_MAY_INSERT);
+}
+
+/* See breakpoint.h. */
+
+struct breakpoint *
+create_and_insert_solib_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+ struct breakpoint *b;
+
+ /* Explicitly tell update_global_location_list to insert
+ locations. */
+ b = create_solib_event_breakpoint_1 (gdbarch, address, UGLL_INSERT);
+ if (!b->loc->inserted)
+ {
+ delete_breakpoint (b);
+ return NULL;
+ }
return b;
}
|| (is_tracepoint (b)))
&& loc->pspace == current_program_space
&& !loc->shlib_disabled
-#ifdef PC_SOLIB
- && PC_SOLIB (loc->address)
-#else
&& solib_name_from_address (loc->pspace, loc->address)
-#endif
)
{
loc->shlib_disabled = 1;
}
}
-/* Disable any breakpoints and tracepoints that are in an unloaded shared
- library. Only apply to enabled breakpoints, disabled ones can just stay
- disabled. */
+/* Disable any breakpoints and tracepoints that are in SOLIB upon
+ notification of unloaded_shlib. Only apply to enabled breakpoints,
+ disabled ones can just stay disabled. */
static void
disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
}
}
+/* Disable any breakpoints and tracepoints in OBJFILE upon
+ notification of free_objfile. Only apply to enabled breakpoints,
+ disabled ones can just stay disabled. */
+
+static void
+disable_breakpoints_in_freed_objfile (struct objfile *objfile)
+{
+ struct breakpoint *b;
+
+ if (objfile == NULL)
+ return;
+
+ /* OBJF_SHARED|OBJF_USERLOADED objfiles are dynamic modules manually
+ managed by the user with add-symbol-file/remove-symbol-file.
+ Similarly to how breakpoints in shared libraries are handled in
+ response to "nosharedlibrary", mark breakpoints in such modules
+ shlib_disabled so they end up uninserted on the next global
+ location list update. Shared libraries not loaded by the user
+ aren't handled here -- they're already handled in
+ disable_breakpoints_in_unloaded_shlib, called by solib.c's
+ solib_unloaded observer. We skip objfiles that are not
+ OBJF_SHARED as those aren't considered dynamic objects (e.g. the
+ main objfile). */
+ if ((objfile->flags & OBJF_SHARED) == 0
+ || (objfile->flags & OBJF_USERLOADED) == 0)
+ return;
+
+ ALL_BREAKPOINTS (b)
+ {
+ struct bp_location *loc;
+ int bp_modified = 0;
+
+ if (!is_breakpoint (b) && !is_tracepoint (b))
+ continue;
+
+ for (loc = b->loc; loc != NULL; loc = loc->next)
+ {
+ CORE_ADDR loc_addr = loc->address;
+
+ if (loc->loc_type != bp_loc_hardware_breakpoint
+ && loc->loc_type != bp_loc_software_breakpoint)
+ continue;
+
+ if (loc->shlib_disabled != 0)
+ continue;
+
+ if (objfile->pspace != loc->pspace)
+ continue;
+
+ if (loc->loc_type != bp_loc_hardware_breakpoint
+ && loc->loc_type != bp_loc_software_breakpoint)
+ continue;
+
+ if (is_addr_in_objfile (loc_addr, objfile))
+ {
+ loc->shlib_disabled = 1;
+ /* At this point, we don't know whether the object was
+ unmapped from the inferior or not, so leave the
+ inserted flag alone. We'll handle failure to
+ uninsert quietly, in case the object was indeed
+ unmapped. */
+
+ mark_breakpoint_location_modified (loc);
+
+ bp_modified = 1;
+ }
+ }
+
+ if (bp_modified)
+ observer_notify_breakpoint_modified (b);
+ }
+}
+
/* FORK & VFORK catchpoints. */
/* An instance of this type is used to represent a fork or vfork
static int
insert_catch_fork (struct bp_location *bl)
{
- return target_insert_fork_catchpoint (PIDGET (inferior_ptid));
+ return target_insert_fork_catchpoint (ptid_get_pid (inferior_ptid));
}
/* Implement the "remove" breakpoint_ops method for fork
static int
remove_catch_fork (struct bp_location *bl)
{
- return target_remove_fork_catchpoint (PIDGET (inferior_ptid));
+ return target_remove_fork_catchpoint (ptid_get_pid (inferior_ptid));
}
/* Implement the "breakpoint_hit" 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", "fork");
}
/* Implement the "print_mention" breakpoint_ops method for fork
static int
insert_catch_vfork (struct bp_location *bl)
{
- return target_insert_vfork_catchpoint (PIDGET (inferior_ptid));
+ return target_insert_vfork_catchpoint (ptid_get_pid (inferior_ptid));
}
/* Implement the "remove" breakpoint_ops method for vfork
static int
remove_catch_vfork (struct bp_location *bl)
{
- return target_remove_vfork_catchpoint (PIDGET (inferior_ptid));
+ return target_remove_vfork_catchpoint (ptid_get_pid (inferior_ptid));
}
/* Implement the "breakpoint_hit" breakpoint_ops method for vfork
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;
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);
- discard_cleanups (cleanup);
- install_breakpoint (0, &c->base, 1);
+ 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_or_unload (arg, from_tty, 0, command);
}
-DEF_VEC_I(int);
-
/* An instance of this type is used to represent a syscall catchpoint.
It includes a "struct breakpoint" as a kind of base class; users
downcast to "struct breakpoint *" when needed. A breakpoint is
inf_data = inferior_data (inf, catch_syscall_inferior_data);
if (inf_data == NULL)
{
- inf_data = XZALLOC (struct catch_syscall_inferior_data);
+ inf_data = XCNEW (struct catch_syscall_inferior_data);
set_inferior_data (inf, catch_syscall_inferior_data, inf_data);
}
}
}
- return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
inf_data->total_syscalls_count != 0,
inf_data->any_syscall_count,
VEC_length (int,
}
}
- return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
inf_data->total_syscalls_count != 0,
inf_data->any_syscall_count,
VEC_length (int,
VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
i++)
if (syscall_number == iter)
- break;
- /* Not the same. */
- if (!iter)
- return 0;
+ return 1;
+
+ return 0;
}
return 1;
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);
if (update_gll)
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
static void
static int
insert_catch_exec (struct bp_location *bl)
{
- return target_insert_exec_catchpoint (PIDGET (inferior_ptid));
+ return target_insert_exec_catchpoint (ptid_get_pid (inferior_ptid));
}
static int
remove_catch_exec (struct bp_location *bl)
{
- return target_remove_exec_catchpoint (PIDGET (inferior_ptid));
+ return target_remove_exec_catchpoint (ptid_get_pid (inferior_ptid));
}
static int
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
if (is_watchpoint (b) && breakpoint_enabled (b))
{
b->enable_state = bp_call_disabled;
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
}
}
}
if (is_watchpoint (b) && b->enable_state == bp_call_disabled)
{
b->enable_state = bp_enabled;
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
}
}
disable_breakpoints_before_startup (void)
{
current_program_space->executing_startup = 1;
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
}
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;
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
- update_global_location_list_nothrow (1);
+ update_global_location_list_nothrow (UGLL_MAY_INSERT);
return b;
}
/* Make a momentary breakpoint based on the master breakpoint ORIG.
- The new breakpoint will have type TYPE, and use OPS as it
- breakpoint_ops. */
+ The new breakpoint will have type TYPE, use OPS as its
+ breakpoint_ops, and will set enabled to LOC_ENABLED. */
static struct breakpoint *
momentary_breakpoint_from_master (struct breakpoint *orig,
enum bptype type,
- const struct breakpoint_ops *ops)
+ const struct breakpoint_ops *ops,
+ int loc_enabled)
{
struct breakpoint *copy;
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
copy->loc->probe = orig->loc->probe;
-
- if (orig->loc->source_file != NULL)
- copy->loc->source_file = xstrdup (orig->loc->source_file);
-
copy->loc->line_number = orig->loc->line_number;
+ copy->loc->symtab = orig->loc->symtab;
+ copy->loc->enabled = loc_enabled;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
copy->pspace = orig->pspace;
copy->disposition = disp_donttouch;
copy->number = internal_breakpoint_number--;
- update_global_location_list_nothrow (0);
+ update_global_location_list_nothrow (UGLL_DONT_INSERT);
return copy;
}
if (orig == NULL)
return NULL;
- return momentary_breakpoint_from_master (orig, orig->type, orig->ops);
+ return momentary_breakpoint_from_master (orig, orig->type, orig->ops, 0);
}
struct breakpoint *
adjusted_address = adjust_breakpoint_address (loc_gdbarch,
sal->pc, b->type);
+ /* Sort the locations by their ADDRESS. */
loc = allocate_bp_location (b);
- for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
+ for (tmp = &(b->loc); *tmp != NULL && (*tmp)->address <= adjusted_address;
+ tmp = &((*tmp)->next))
;
+ loc->next = *tmp;
*tmp = loc;
loc->requested_address = sal->pc;
loc->address = adjusted_address;
loc->pspace = sal->pspace;
- loc->probe = sal->probe;
+ loc->probe.probe = sal->probe;
+ loc->probe.objfile = sal->objfile;
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;
}
-/* 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. (Future
- styles may include the ability to do a target-side printf.) */
-
-static const char dprintf_style_gdb[] = "gdb";
-static const char dprintf_style_call[] = "call";
-static const char *const dprintf_style_enums[] = {
- dprintf_style_gdb,
- dprintf_style_call,
- 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 = "";
-
/* Build a command list for the dprintf corresponding to the current
settings of the dprintf style options. */
if (*dprintf_args != '"')
error (_("Bad format string, missing '\"'."));
- if (strcmp (dprintf_style, "gdb") == 0)
+ if (strcmp (dprintf_style, dprintf_style_gdb) == 0)
printf_line = xstrprintf ("printf %s", dprintf_args);
- else if (strcmp (dprintf_style, "call") == 0)
+ else if (strcmp (dprintf_style, dprintf_style_call) == 0)
{
if (!dprintf_function)
error (_("No function supplied for dprintf call"));
dprintf_function,
dprintf_args);
}
+ else if (strcmp (dprintf_style, dprintf_style_agent) == 0)
+ {
+ if (target_can_run_breakpoint_commands ())
+ printf_line = xstrprintf ("agent-printf %s", dprintf_args);
+ else
+ {
+ warning (_("Target cannot run dprintf commands, falling back to GDB printf"));
+ printf_line = xstrprintf ("printf %s", dprintf_args);
+ }
+ }
else
internal_error (__FILE__, __LINE__,
_("Invalid dprintf style."));
- /* Manufacture a printf/continue sequence. */
- if (printf_line)
- {
- struct command_line *printf_cmd_line, *cont_cmd_line = NULL;
-
- 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");
+ gdb_assert (printf_line != NULL);
+ /* Manufacture a printf sequence. */
+ {
+ struct command_line *printf_cmd_line
+ = xmalloc (sizeof (struct command_line));
- 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;
+ 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 = NULL;
+ printf_cmd_line->line = printf_line;
- breakpoint_set_commands (b, printf_cmd_line);
- }
+ breakpoint_set_commands (b, printf_cmd_line);
+ }
}
/* Update all dprintf commands, making their command lists reflect
if (b->cond_string)
{
- char *arg = b->cond_string;
+ const char *arg = b->cond_string;
+
loc->cond = parse_exp_1 (&arg, loc->address,
block_for_pc (loc->address), 0);
if (*arg)
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;
}
}
+/* 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.
If no thread is found, *THREAD is set to -1. */
static void
-find_condition_and_thread (char *tok, CORE_ADDR pc,
+find_condition_and_thread (const 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;
+ const char *end_tok;
int toklen;
- char *cond_start = NULL;
- char *cond_end = NULL;
+ const char *cond_start = NULL;
+ const char *cond_end = NULL;
- tok = skip_spaces (tok);
+ tok = skip_spaces_const (tok);
if ((*tok == '"' || *tok == ',') && rest)
{
return;
}
- end_tok = skip_to_space (tok);
+ end_tok = skip_to_space_const (tok);
toklen = end_tok - tok;
char *tmptok;
tok = end_tok + 1;
- tmptok = tok;
- *thread = strtol (tok, &tok, 0);
+ *thread = strtol (tok, &tmptok, 0);
if (tok == tmptok)
error (_("Junk after thread keyword."));
if (!valid_thread_id (*thread))
- error (_("Unknown thread %d."), *thread);
+ invalid_thread_id_error (*thread);
+ tok = tmptok;
}
else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
{
char *tmptok;
tok = end_tok + 1;
- tmptok = tok;
- *task = strtol (tok, &tok, 0);
+ *task = strtol (tok, &tmptok, 0);
if (tok == tmptok)
error (_("Junk after task keyword."));
if (!valid_task_id (*task))
error (_("Unknown task %d."), *task);
+ tok = tmptok;
}
else if (rest)
{
/* Set a breakpoint. This function is shared between CLI and MI
functions for setting a breakpoint. This function has two major
- modes of operations, selected by the PARSE_CONDITION_AND_THREAD
- parameter. If non-zero, the function will parse arg, extracting
- breakpoint location, address and thread. Otherwise, ARG is just
- the location of breakpoint, with condition and thread specified by
- the COND_STRING and THREAD parameters. If INTERNAL is non-zero,
- the breakpoint number will be allocated from the internal
- breakpoint count. Returns true if any breakpoint was created;
- false otherwise. */
+ modes of operations, selected by the PARSE_ARG parameter. If
+ non-zero, the function will parse ARG, extracting location,
+ condition, thread and extra string. Otherwise, ARG is just the
+ breakpoint's location, with condition, thread, and extra string
+ specified by the COND_STRING, THREAD and EXTRA_STRING parameters.
+ If INTERNAL is non-zero, the breakpoint number will be allocated
+ from the internal breakpoint count. Returns true if any breakpoint
+ was created; false otherwise. */
int
create_breakpoint (struct gdbarch *gdbarch,
char *arg, char *cond_string,
int thread, char *extra_string,
- int parse_condition_and_thread,
+ int parse_arg,
int tempflag, enum bptype type_wanted,
int ignore_count,
enum auto_boolean pending_break_support,
breakpoint. */
if (!pending)
{
- struct linespec_sals *lsal;
+ if (parse_arg)
+ {
+ char *rest;
+ struct linespec_sals *lsal;
- lsal = VEC_index (linespec_sals, canonical.sals, 0);
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
- if (parse_condition_and_thread)
- {
- char *rest;
- /* Here we only parse 'arg' to separate condition
- from thread number, so parsing in context of first
- sal is OK. When setting the breakpoint we'll
- re-parse it in context of each sal. */
- cond_string = NULL;
- thread = -1;
- rest = NULL;
- find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
- &thread, &task, &rest);
- if (cond_string)
- make_cleanup (xfree, cond_string);
- if (rest)
- make_cleanup (xfree, rest);
- if (rest)
- extra_string = 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. */
+
+ find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
+ &thread, &task, &rest);
+ if (cond_string)
+ make_cleanup (xfree, cond_string);
+ if (rest)
+ make_cleanup (xfree, rest);
+ if (rest)
+ extra_string = rest;
}
else
{
- /* Create a private copy of condition string. */
- if (cond_string)
- {
- cond_string = xstrdup (cond_string);
- make_cleanup (xfree, cond_string);
- }
- /* Create a private copy of any extra string. */
- if (extra_string)
- {
- extra_string = xstrdup (extra_string);
- make_cleanup (xfree, extra_string);
- }
+ if (*arg != '\0')
+ error (_("Garbage '%s' at end of location"), arg);
+
+ /* Create a private copy of condition string. */
+ if (cond_string)
+ {
+ 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,
+ ops->create_breakpoints_sal (gdbarch, &canonical,
cond_string, extra_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
b->addr_string = copy_arg;
- b->cond_string = NULL;
+ if (parse_arg)
+ 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;
do_cleanups (old_chain);
/* error call may happen here - have BKPT_CHAIN already discarded. */
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
return 1;
}
{
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
if (sal->section == 0 && sal->symtab != NULL)
{
- struct blockvector *bv;
- struct block *b;
+ const struct blockvector *bv;
+ const struct block *b;
struct symbol *sym;
bv = blockvector_for_pc_sect (sal->pc, 0, &b, sal->symtab);
if (sym != NULL)
{
fixup_symbol_section (sym, sal->symtab->objfile);
- sal->section = SYMBOL_OBJ_SECTION (sym);
+ sal->section = SYMBOL_OBJ_SECTION (sal->symtab->objfile, sym);
}
else
{
if we have line numbers but no functions (as can
happen in assembly source). */
- struct minimal_symbol *msym;
+ struct bound_minimal_symbol msym;
struct cleanup *old_chain = save_current_space_and_thread ();
switch_to_program_space_and_thread (sal->pspace);
msym = lookup_minimal_symbol_by_pc (sal->pc);
- if (msym)
- sal->section = SYMBOL_OBJ_SECTION (msym);
+ if (msym.minsym)
+ sal->section = MSYMBOL_OBJ_SECTION (msym.objfile, msym.minsym);
do_cleanups (old_chain);
}
break_command_1 (arg, 0, from_tty);
}
-void dprintf_command (char *arg, int from_tty);
-
/* The dynamic printf command is mostly like a regular breakpoint, but
with a prewired command list consisting of a single output command,
built from extra arguments supplied on the dprintf command
line. */
-void
+static void
dprintf_command (char *arg, int from_tty)
{
create_breakpoint (get_current_arch (),
0);
}
+static void
+agent_printf_command (char *arg, int from_tty)
+{
+ error (_("May only run agent-printf on the target"));
+}
+
/* Implement the "breakpoint_hit" breakpoint_ops method for
ranged breakpoints. */
mention (b);
observer_notify_breakpoint_created (b);
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
/* Return non-zero if EXP is verified as constant. Returned zero
case BINOP_MAX:
case BINOP_INTDIV:
case BINOP_CONCAT:
- case BINOP_IN:
- 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_TYPEID:
case OP_NAME:
case OP_OBJC_NSSTRING:
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_file *stb;
enum print_stop_action result;
struct watchpoint *w;
gdb_assert (bs->bp_location_at != NULL);
- bl = bs->bp_location_at;
b = bs->breakpoint_at;
w = (struct watchpoint *) b;
print_recreate_thread (b, fp);
}
+/* Implement the "explains_signal" breakpoint_ops method for
+ watchpoints. */
+
+static int
+explains_signal_watchpoint (struct breakpoint *b, enum gdb_signal sig)
+{
+ /* A software watchpoint cannot cause a signal other than
+ GDB_SIGNAL_TRAP. */
+ if (b->type == bp_watchpoint && sig != GDB_SIGNAL_TRAP)
+ return 0;
+
+ return 1;
+}
+
/* The breakpoint_ops structure to be used in hardware watchpoints. */
static struct breakpoint_ops watchpoint_breakpoint_ops;
hw_read: watch read,
hw_access: watch access (read or write) */
static void
-watch_command_1 (char *arg, int accessflag, int from_tty,
+watch_command_1 (const char *arg, int accessflag, int from_tty,
int just_location, int internal)
{
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;
+ int saved_bitpos = 0, saved_bitsize = 0;
struct frame_info *frame;
- char *exp_start = NULL;
- char *exp_end = NULL;
- char *tok, *end_tok;
+ const char *exp_start = NULL;
+ const char *exp_end = NULL;
+ const char *tok, *end_tok;
int toklen = -1;
- char *cond_start = NULL;
- char *cond_end = NULL;
+ const char *cond_start = NULL;
+ const char *cond_end = NULL;
enum bptype bp_type;
int thread = -1;
int pc = 0;
int use_mask = 0;
CORE_ADDR mask = 0;
struct watchpoint *w;
+ char *expression;
+ struct cleanup *back_to;
/* Make sure that we actually have parameters to parse. */
if (arg != NULL && arg[0] != '\0')
{
- char *value_start;
+ const char *value_start;
+
+ exp_end = arg + strlen (arg);
/* Look for "parameter value" pairs at the end
of the arguments string. */
- for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+ for (tok = exp_end - 1; tok > arg; tok--)
{
/* Skip whitespace at the end of the argument list. */
while (tok > arg && (*tok == ' ' || *tok == '\t'))
/* 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))
{
/* Truncate the string and get rid of the "parameter value" pair before
the arguments string is parsed by the parse_exp_1 function. */
- *tok = '\0';
+ exp_end = tok;
}
}
+ else
+ exp_end = arg;
- /* Parse the rest of the arguments. */
+ /* Parse the rest of the arguments. From here on out, everything
+ is in terms of a newly allocated string instead of the original
+ ARG. */
innermost_block = NULL;
- exp_start = arg;
+ expression = savestring (arg, exp_end - arg);
+ back_to = make_cleanup (xfree, expression);
+ exp_start = arg = expression;
exp = parse_exp_1 (&arg, 0, 0, 0);
exp_end = arg;
/* Remove trailing whitespace from the expression before saving it.
exp_valid_block = innermost_block;
mark = value_mark ();
- fetch_subexp_value (exp, &pc, &val, &result, NULL);
+ fetch_subexp_value (exp, &pc, &val, &result, NULL, just_location);
+
+ if (val != NULL && just_location)
+ {
+ saved_bitpos = value_bitpos (val);
+ saved_bitsize = value_bitsize (val);
+ }
if (just_location)
{
else if (val != NULL)
release_value (val);
- tok = skip_spaces (arg);
- end_tok = skip_to_space (tok);
+ tok = skip_spaces_const (arg);
+ end_tok = skip_to_space_const (tok);
toklen = end_tok - tok;
if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
if (*tok)
error (_("Junk at end of command."));
- if (accessflag == hw_read)
- bp_type = bp_read_watchpoint;
- else if (accessflag == hw_access)
- bp_type = bp_access_watchpoint;
- else
- bp_type = bp_hardware_watchpoint;
-
frame = block_innermost_frame (exp_valid_block);
/* If the expression is "local", then set up a "watchpoint scope"
}
}
- /* Now set up the breakpoint. */
+ /* Now set up the breakpoint. We create all watchpoints as hardware
+ watchpoints here even if hardware watchpoints are turned off, a call
+ to update_watchpoint later in this function will cause the type to
+ drop back to bp_watchpoint (software watchpoint) if required. */
+
+ if (accessflag == hw_read)
+ bp_type = bp_read_watchpoint;
+ else if (accessflag == hw_access)
+ bp_type = bp_access_watchpoint;
+ else
+ bp_type = bp_hardware_watchpoint;
w = XCNEW (struct watchpoint);
b = &w->base;
else
{
w->val = val;
+ w->val_bitpos = saved_bitpos;
+ w->val_bitsize = saved_bitsize;
w->val_valid = 1;
}
}
install_breakpoint (internal, b, 1);
+ do_cleanups (back_to);
}
/* Return count of debug registers needed to watch the given expression.
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. */
int thread;
struct thread_info *tp;
- clear_proceed_status ();
+ clear_proceed_status (0);
/* Set a breakpoint where the user wants it and at return from
this function. */
it updates arg to point to the first character following the parsed
if clause in the arg string. */
-static char *
+char *
ep_parse_optional_if_clause (char **arg)
{
char *cond_string;
error (_("Junk at end of arguments."));
/* If this target supports it, create a fork or vfork catchpoint
- and enable reporting of such events. */
- switch (fork_kind)
- {
- case catch_fork_temporary:
- case catch_fork_permanent:
- create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
- &catch_fork_breakpoint_ops);
- break;
- case catch_vfork_temporary:
- case catch_vfork_permanent:
- create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
- &catch_vfork_breakpoint_ops);
- break;
- default:
- error (_("unsupported or unknown fork kind; cannot catch it"));
- break;
- }
-}
-
-static void
-catch_exec_command_1 (char *arg, int from_tty,
- struct cmd_list_element *command)
-{
- struct exec_catchpoint *c;
- struct gdbarch *gdbarch = get_current_arch ();
- int tempflag;
- char *cond_string = NULL;
-
- tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
-
- if (!arg)
- arg = "";
- arg = skip_spaces (arg);
-
- /* The allowed syntax is:
- catch exec
- catch exec if <cond>
-
- First, check if there's an if clause. */
- cond_string = ep_parse_optional_if_clause (&arg);
-
- if ((*arg != '\0') && !isspace (*arg))
- error (_("Junk at end of arguments."));
-
- c = XNEW (struct exec_catchpoint);
- init_catchpoint (&c->base, gdbarch, tempflag, cond_string,
- &catch_exec_breakpoint_ops);
- c->exec_pathname = NULL;
-
- install_breakpoint (0, &c->base, 1);
-}
-
-static enum print_stop_action
-print_it_exception_catchpoint (bpstat bs)
-{
- struct ui_out *uiout = current_uiout;
- struct breakpoint *b = bs->breakpoint_at;
- int bp_temp, bp_throw;
-
- annotate_catchpoint (b->number);
-
- bp_throw = strstr (b->addr_string, "throw") != NULL;
- if (b->loc->address != b->loc->requested_address)
- breakpoint_adjustment_warning (b->loc->requested_address,
- b->loc->address,
- b->number, 1);
- bp_temp = b->disposition == disp_del;
- ui_out_text (uiout,
- bp_temp ? "Temporary catchpoint "
- : "Catchpoint ");
- if (!ui_out_is_mi_like_p (uiout))
- ui_out_field_int (uiout, "bkptno", b->number);
- ui_out_text (uiout,
- bp_throw ? " (exception thrown), "
- : " (exception caught), ");
- if (ui_out_is_mi_like_p (uiout))
- {
- ui_out_field_string (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
- ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
- ui_out_field_int (uiout, "bkptno", b->number);
- }
- return PRINT_SRC_AND_LOC;
-}
-
-static void
-print_one_exception_catchpoint (struct breakpoint *b,
- struct bp_location **last_loc)
-{
- struct value_print_options opts;
- struct ui_out *uiout = current_uiout;
-
- get_user_print_options (&opts);
- if (opts.addressprint)
- {
- annotate_field (4);
- if (b->loc == NULL || b->loc->shlib_disabled)
- ui_out_field_string (uiout, "addr", "<PENDING>");
- else
- ui_out_field_core_addr (uiout, "addr",
- b->loc->gdbarch, b->loc->address);
- }
- annotate_field (5);
- if (b->loc)
- *last_loc = b->loc;
- if (strstr (b->addr_string, "throw") != NULL)
- ui_out_field_string (uiout, "what", "exception throw");
- else
- ui_out_field_string (uiout, "what", "exception catch");
-}
-
-static void
-print_mention_exception_catchpoint (struct breakpoint *b)
-{
- struct ui_out *uiout = current_uiout;
- int bp_temp;
- int bp_throw;
-
- bp_temp = b->disposition == disp_del;
- bp_throw = strstr (b->addr_string, "throw") != NULL;
- ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
- : _("Catchpoint "));
- ui_out_field_int (uiout, "bkptno", b->number);
- ui_out_text (uiout, bp_throw ? _(" (throw)")
- : _(" (catch)"));
-}
-
-/* Implement the "print_recreate" breakpoint_ops method for throw and
- catch catchpoints. */
-
-static void
-print_recreate_exception_catchpoint (struct breakpoint *b,
- struct ui_file *fp)
-{
- int bp_temp;
- int bp_throw;
-
- bp_temp = b->disposition == disp_del;
- bp_throw = strstr (b->addr_string, "throw") != NULL;
- fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
- fprintf_unfiltered (fp, bp_throw ? "throw" : "catch");
- print_recreate_thread (b, fp);
-}
-
-static struct breakpoint_ops gnu_v3_exception_catchpoint_ops;
-
-static int
-handle_gnu_v3_exceptions (int tempflag, char *cond_string,
- enum exception_event_kind ex_event, int from_tty)
-{
- char *trigger_func_name;
-
- if (ex_event == EX_EVENT_CATCH)
- trigger_func_name = "__cxa_begin_catch";
- else
- trigger_func_name = "__cxa_throw";
-
- create_breakpoint (get_current_arch (),
- 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);
-
- return 1;
+ and enable reporting of such events. */
+ switch (fork_kind)
+ {
+ case catch_fork_temporary:
+ case catch_fork_permanent:
+ create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
+ &catch_fork_breakpoint_ops);
+ break;
+ case catch_vfork_temporary:
+ case catch_vfork_permanent:
+ create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
+ &catch_vfork_breakpoint_ops);
+ break;
+ default:
+ error (_("unsupported or unknown fork kind; cannot catch it"));
+ break;
+ }
}
-/* Deal with "catch catch" and "catch throw" commands. */
-
static void
-catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
- int tempflag, int from_tty)
+catch_exec_command_1 (char *arg, int from_tty,
+ struct cmd_list_element *command)
{
+ struct exec_catchpoint *c;
+ struct gdbarch *gdbarch = get_current_arch ();
+ int tempflag;
char *cond_string = NULL;
+ tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
if (!arg)
arg = "";
arg = skip_spaces (arg);
+ /* The allowed syntax is:
+ catch exec
+ catch exec if <cond>
+
+ First, check if there's an if clause. */
cond_string = ep_parse_optional_if_clause (&arg);
if ((*arg != '\0') && !isspace (*arg))
error (_("Junk at end of arguments."));
- if (ex_event != EX_EVENT_THROW
- && ex_event != EX_EVENT_CATCH)
- error (_("Unsupported or unknown exception event; cannot catch it"));
-
- if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
- return;
-
- warning (_("Unsupported with this platform/compiler combination."));
-}
-
-/* Implementation of "catch catch" command. */
-
-static void
-catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command)
-{
- int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
-
- catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
-}
-
-/* Implementation of "catch throw" command. */
-
-static void
-catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
-{
- int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+ c = XNEW (struct exec_catchpoint);
+ init_catchpoint (&c->base, gdbarch, tempflag, cond_string,
+ &catch_exec_breakpoint_ops);
+ c->exec_pathname = NULL;
- catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
+ install_breakpoint (0, &c->base, 1);
}
void
char *addr_string,
const struct breakpoint_ops *ops,
int tempflag,
+ int enabled,
int from_tty)
{
if (from_tty)
init_raw_breakpoint (b, gdbarch, sal, bp_breakpoint, ops);
- b->enable_state = bp_enabled;
+ b->enable_state = enabled ? bp_enabled : bp_disabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->addr_string = addr_string;
b->language = language_ada;
struct syscall s;
/* Skip whitespace. */
- while (isspace (*arg))
- arg++;
+ arg = skip_spaces (arg);
for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
cur_name[i] = arg[i];
the number 0. */
if (ua < ub)
return -1;
- return ub > ub ? 1 : 0;
+ return ua > ub ? 1 : 0;
}
/* Delete breakpoints by address or line. */
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++)
{
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);
}
}
}
+/* Called whether new breakpoints are created, or existing breakpoints
+ deleted, to update the global location list and recompute which
+ locations are duplicate of which.
-/* 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
- breakpoints should pass false, so that deleting a breakpoint
- doesn't have the side effect of inserting the locations of other
- breakpoints that are marked not-inserted, but should_be_inserted
- returns true on them.
-
- This behaviour is useful is situations close to tear-down -- e.g.,
- after an exec, while the target still has execution, but breakpoint
- shadows of the previous executable image should *NOT* be restored
- to the new image; or before detaching, where the target still has
- execution and wants to delete breakpoints from GDB's lists, and all
- breakpoints had already been removed from the inferior. */
+ The INSERT_MODE flag determines whether locations may not, may, or
+ shall be inserted now. See 'enum ugll_insert_mode' for more
+ info. */
static void
-update_global_location_list (int should_insert)
+update_global_location_list (enum ugll_insert_mode insert_mode)
{
struct breakpoint *b;
struct bp_location **locp, *loc;
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
"a permanent breakpoint"));
}
- if (breakpoints_always_inserted_mode ()
- && (have_live_inferiors ()
- || (gdbarch_has_global_breakpoints (target_gdbarch))))
+ if (insert_mode == UGLL_INSERT || breakpoints_should_be_inserted_now ())
{
- if (should_insert)
+ if (insert_mode != UGLL_DONT_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
+ /* Even though the caller told us to not insert new
+ locations, we may still need to update conditions on the
+ target's side of breakpoints that were already inserted
+ if the target is evaluating breakpoint conditions. We
only update conditions for locations that are marked
"needs_update". */
update_inserted_breakpoint_locations ();
}
}
- if (should_insert)
+ if (insert_mode != UGLL_DONT_INSERT)
download_tracepoint_locations ();
do_cleanups (cleanups);
}
static void
-update_global_location_list_nothrow (int inserting)
+update_global_location_list_nothrow (enum ugll_insert_mode insert_mode)
{
volatile struct gdb_exception e;
TRY_CATCH (e, RETURN_MASK_ERROR)
- update_global_location_list (inserting);
+ update_global_location_list (insert_mode);
}
/* Clear BKP from a BPS. */
static void
say_where (struct breakpoint *b)
{
- struct ui_out *uiout = current_uiout;
struct value_print_options opts;
get_user_print_options (&opts);
}
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
if (self->cond_bytecode)
free_agent_expr (self->cond_bytecode);
xfree (self->function_name);
- xfree (self->source_file);
+
+ VEC_free (agent_expr_p, self->target_info.conditions);
+ VEC_free (agent_expr_p, self->target_info.tcommands);
}
static const struct bp_location_ops bp_location_ops =
{
decref_counted_command_line (&self->commands);
xfree (self->cond_string);
+ xfree (self->extra_string);
xfree (self->addr_string);
xfree (self->filter);
xfree (self->addr_string_range_end);
static void
base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch,
struct linespec_result *c,
- struct linespec_sals *lsal,
char *cond_string,
char *extra_string,
enum bptype type_wanted,
internal_error_pure_virtual_called ();
}
-static struct breakpoint_ops base_breakpoint_ops =
+/* The default 'explains_signal' method. */
+
+static int
+base_breakpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig)
+{
+ return 1;
+}
+
+/* The default "after_condition_true" method. */
+
+static void
+base_breakpoint_after_condition_true (struct bpstats *bs)
+{
+ /* Nothing to do. */
+}
+
+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,
+ base_breakpoint_after_condition_true,
};
/* Default breakpoint_ops methods. */
breakpoint_re_set_default (b);
}
+/* Copy SRC's shadow buffer and whatever else we'd set if we actually
+ inserted DEST, so we can remove it later, in case SRC is removed
+ first. */
+
+static void
+bp_target_info_copy_insertion_state (struct bp_target_info *dest,
+ const struct bp_target_info *src)
+{
+ dest->shadow_len = src->shadow_len;
+ memcpy (dest->shadow_contents, src->shadow_contents, src->shadow_len);
+ dest->placed_address = src->placed_address;
+ dest->placed_size = src->placed_size;
+}
+
static int
bkpt_insert_location (struct bp_location *bl)
{
return target_insert_hw_breakpoint (bl->gdbarch,
&bl->target_info);
else
- return target_insert_breakpoint (bl->gdbarch,
- &bl->target_info);
+ {
+ struct bp_target_info *bp_tgt = &bl->target_info;
+ int ret;
+ int sss_slot;
+
+ /* There is no need to insert a breakpoint if an unconditional
+ raw/sss breakpoint is already inserted at that location. */
+ sss_slot = find_single_step_breakpoint (bp_tgt->placed_address_space,
+ bp_tgt->reqstd_address);
+ if (sss_slot >= 0)
+ {
+ struct bp_target_info *sss_bp_tgt = single_step_breakpoints[sss_slot];
+
+ bp_target_info_copy_insertion_state (bp_tgt, sss_bp_tgt);
+ return 0;
+ }
+
+ return target_insert_breakpoint (bl->gdbarch, bp_tgt);
+ }
}
static int
if (bl->loc_type == bp_loc_hardware_breakpoint)
return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
else
- return target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+ {
+ struct bp_target_info *bp_tgt = &bl->target_info;
+ struct address_space *aspace = bp_tgt->placed_address_space;
+ CORE_ADDR address = bp_tgt->reqstd_address;
+
+ /* Only remove the breakpoint if there is no raw/sss breakpoint
+ still inserted at this location. Otherwise, we would be
+ effectively disabling the raw/sss breakpoint. */
+ if (single_step_breakpoint_inserted_here_p (aspace, address))
+ return 0;
+
+ return target_remove_breakpoint (bl->gdbarch, bp_tgt);
+ }
}
static int
struct address_space *aspace, CORE_ADDR bp_addr,
const struct target_waitstatus *ws)
{
- struct breakpoint *b = bl->owner;
-
if (ws->kind != TARGET_WAITKIND_STOPPED
|| ws->value.sig != GDB_SIGNAL_TRAP)
return 0;
}
static int
+dprintf_breakpoint_hit (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr,
+ const struct target_waitstatus *ws)
+{
+ if (dprintf_style == dprintf_style_agent
+ && target_can_run_breakpoint_commands ())
+ {
+ /* An agent-style dprintf never causes a stop. If we see a trap
+ for this address it must be for a breakpoint that happens to
+ be set at the same address. */
+ return 0;
+ }
+
+ return bkpt_breakpoint_hit (bl, aspace, bp_addr, ws);
+}
+
+static int
bkpt_resources_needed (const struct bp_location *bl)
{
gdb_assert (bl->owner->type == bp_hardware_breakpoint);
static void
bkpt_create_breakpoints_sal (struct gdbarch *gdbarch,
struct linespec_result *canonical,
- struct linespec_sals *lsal,
char *cond_string,
char *extra_string,
enum bptype type_wanted,
int from_tty, int enabled,
int internal, unsigned flags)
{
- create_breakpoints_sal_default (gdbarch, canonical, lsal,
+ create_breakpoints_sal_default (gdbarch, canonical,
cond_string, extra_string,
type_wanted,
disposition, thread, task,
static enum print_stop_action
internal_bkpt_print_it (bpstat bs)
{
- struct ui_out *uiout = current_uiout;
struct breakpoint *b;
b = bs->breakpoint_at;
momentary_bkpt_re_set (struct breakpoint *b)
{
/* Keep temporary breakpoints, which can be encountered when we step
- over a dlopen call and SOLIB_ADD is resetting the breakpoints.
+ over a dlopen call and solib_add is resetting the breakpoints.
Otherwise these should have been blown away via the cleanup chain
or by breakpoint_init_inferior when we rerun the executable. */
}
{
/* The insertion was successful, now let's set the probe's semaphore
if needed. */
- bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch);
+ bl->probe.probe->pops->set_semaphore (bl->probe.probe,
+ bl->probe.objfile,
+ bl->gdbarch);
}
return v;
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);
+ bl->probe.probe->pops->clear_semaphore (bl->probe.probe,
+ bl->probe.objfile,
+ bl->gdbarch);
return bkpt_remove_location (bl);
}
static void
tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch,
struct linespec_result *canonical,
- struct linespec_sals *lsal,
char *cond_string,
char *extra_string,
enum bptype type_wanted,
int from_tty, int enabled,
int internal, unsigned flags)
{
- create_breakpoints_sal_default (gdbarch, canonical, lsal,
+ create_breakpoints_sal_default (gdbarch, canonical,
cond_string, extra_string,
type_wanted,
disposition, thread, task,
static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
+/* Dprintf breakpoint_ops methods. */
+
+static void
+dprintf_re_set (struct breakpoint *b)
+{
+ breakpoint_re_set_default (b);
+
+ /* This breakpoint could have been pending, and be resolved now, and
+ if so, we should now have the extra string. If we don't, the
+ dprintf was malformed when created, but we couldn't tell because
+ we can't extract the extra string until the location is
+ resolved. */
+ if (b->loc != NULL && b->extra_string == NULL)
+ error (_("Format string required"));
+
+ /* 1 - connect to target 1, that can run breakpoint commands.
+ 2 - create a dprintf, which resolves fine.
+ 3 - disconnect from target 1
+ 4 - connect to target 2, that can NOT run breakpoint commands.
+
+ After steps #3/#4, you'll want the dprintf command list to
+ be updated, because target 1 and 2 may well return different
+ answers for target_can_run_breakpoint_commands().
+ Given absence of finer grained resetting, we get to do
+ it all the time. */
+ if (b->extra_string != NULL)
+ update_dprintf_command_list (b);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for dprintf. */
+
+static void
+dprintf_print_recreate (struct breakpoint *tp, struct ui_file *fp)
+{
+ fprintf_unfiltered (fp, "dprintf %s%s", tp->addr_string,
+ tp->extra_string);
+ print_recreate_thread (tp, fp);
+}
+
+/* Implement the "after_condition_true" breakpoint_ops method for
+ dprintf.
+
+ dprintf's are implemented with regular commands in their command
+ list, but we run the commands here instead of before presenting the
+ stop to the user, as dprintf's don't actually cause a stop. This
+ also makes it so that the commands of multiple dprintfs at the same
+ address are all handled. */
+
+static void
+dprintf_after_condition_true (struct bpstats *bs)
+{
+ struct cleanup *old_chain;
+ struct bpstats tmp_bs = { NULL };
+ struct bpstats *tmp_bs_p = &tmp_bs;
+
+ /* dprintf's never cause a stop. This wasn't set in the
+ check_status hook instead because that would make the dprintf's
+ condition not be evaluated. */
+ bs->stop = 0;
+
+ /* Run the command list here. Take ownership of it instead of
+ copying. We never want these commands to run later in
+ bpstat_do_actions, if a breakpoint that causes a stop happens to
+ be set at same address as this dprintf, or even if running the
+ commands here throws. */
+ tmp_bs.commands = bs->commands;
+ bs->commands = NULL;
+ old_chain = make_cleanup_decref_counted_command_line (&tmp_bs.commands);
+
+ bpstat_do_actions_1 (&tmp_bs_p);
+
+ /* 'tmp_bs.commands' will usually be NULL by now, but
+ bpstat_do_actions_1 may return early without processing the whole
+ list. */
+ do_cleanups (old_chain);
+}
+
/* The breakpoint_ops structure to be used on static tracepoints with
markers (`-m'). */
static void
strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
struct linespec_result *canonical,
- struct linespec_sals *lsal,
char *cond_string,
char *extra_string,
enum bptype type_wanted,
int internal, unsigned flags)
{
int i;
+ struct linespec_sals *lsal = VEC_index (linespec_sals,
+ canonical->sals, 0);
/* If the user is creating a static tracepoint by marker id
(strace -m MARKER_ID), then store the sals index, so that
itself, since remove_breakpoint looks at location's owner. It
might be better design to have location completely
self-contained, but it's not the case now. */
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
bpt->ops->dtor (bpt);
/* On the chance that someone will soon try again to delete this
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
/* Ranged breakpoints have only one start location and one end
location. */
b->enable_state = bp_disabled;
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
printf_unfiltered (_("Could not reset ranged breakpoint %d: "
"multiple locations found\n"),
b->number);
old symtab. */
if (b->cond_string != NULL)
{
- char *s;
+ const char *s;
volatile struct gdb_exception e;
s = b->cond_string;
if (!locations_are_equal (existing_locations, b->loc))
observer_notify_breakpoint_modified (b);
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
/* Find the SaL locations corresponding to the given ADDR_STRING.
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 *extra_string = NULL;
+ char *cond_string, *extra_string;
+ int thread, task;
find_condition_and_thread (s, sals.sals[0].pc,
&cond_string, &thread, &task,
static void
create_breakpoints_sal_default (struct gdbarch *gdbarch,
struct linespec_result *canonical,
- struct linespec_sals *lsal,
char *cond_string,
char *extra_string,
enum bptype type_wanted,
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;
}
while (!state.finished)
{
- char *p = state.string;
+ const char *p = state.string;
match = 0;
target_disable_tracepoint (location);
}
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
observer_notify_breakpoint_modified (bpt);
}
if (user_breakpoint_p (bpt))
disable_breakpoint (bpt);
}
- else if (strchr (args, '.'))
+ else
{
- struct bp_location *loc = find_location_by_number (args);
- if (loc)
+ char *num = extract_arg (&args);
+
+ while (num)
{
- if (loc->enabled)
+ if (strchr (num, '.'))
{
- loc->enabled = 0;
- mark_breakpoint_location_modified (loc);
+ struct bp_location *loc = find_location_by_number (num);
+
+ if (loc)
+ {
+ 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))
+ target_disable_tracepoint (loc);
+ }
+ update_global_location_list (UGLL_DONT_INSERT);
}
- if (target_supports_enable_disable_tracepoint ()
- && current_trace_status ()->running && loc->owner
- && is_tracepoint (loc->owner))
- target_disable_tracepoint (loc);
+ else
+ map_breakpoint_numbers (num, do_map_disable_breakpoint, NULL);
+ num = extract_arg (&args);
}
- update_global_location_list (0);
}
- else
- map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
}
static void
bpt->disposition = disposition;
bpt->enable_count = count;
- update_global_location_list (1);
- breakpoints_changed ();
-
+ update_global_location_list (UGLL_MAY_INSERT);
+
observer_notify_breakpoint_modified (bpt);
}
if (user_breakpoint_p (bpt))
enable_breakpoint (bpt);
}
- else if (strchr (args, '.'))
+ else
{
- struct bp_location *loc = find_location_by_number (args);
- if (loc)
+ char *num = extract_arg (&args);
+
+ while (num)
{
- if (!loc->enabled)
+ if (strchr (num, '.'))
{
- loc->enabled = 1;
- mark_breakpoint_location_modified (loc);
+ struct bp_location *loc = find_location_by_number (num);
+
+ if (loc)
+ {
+ 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))
+ target_enable_tracepoint (loc);
+ }
+ update_global_location_list (UGLL_MAY_INSERT);
}
- if (target_supports_enable_disable_tracepoint ()
- && current_trace_status ()->running && loc->owner
- && is_tracepoint (loc->owner))
- target_enable_tracepoint (loc);
+ else
+ map_breakpoint_numbers (num, do_map_enable_breakpoint, NULL);
+ num = extract_arg (&args);
}
- update_global_location_list (1);
}
- else
- map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
}
/* This struct packages up disposition data for application to multiple
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;
struct address_space *aspace, CORE_ADDR pc)
{
struct bp_target_info *bp_tgt;
+ struct bp_location *bl;
- bp_tgt = XZALLOC (struct bp_target_info);
+ bp_tgt = XCNEW (struct bp_target_info);
bp_tgt->placed_address_space = aspace;
- bp_tgt->placed_address = pc;
+ bp_tgt->reqstd_address = pc;
+
+ /* If an unconditional non-raw breakpoint is already inserted at
+ that location, there's no need to insert another. However, with
+ target-side evaluation of breakpoint conditions, if the
+ breakpoint that is currently inserted on the target is
+ conditional, we need to make it unconditional. Note that a
+ breakpoint with target-side commands is not reported even if
+ unconditional, so we need to remove the commands from the target
+ as well. */
+ bl = find_non_raw_software_breakpoint_inserted_here (aspace, pc);
+ if (bl != NULL
+ && VEC_empty (agent_expr_p, bl->target_info.conditions)
+ && VEC_empty (agent_expr_p, bl->target_info.tcommands))
+ {
+ bp_target_info_copy_insertion_state (bp_tgt, &bl->target_info);
+ return bp_tgt;
+ }
if (target_insert_breakpoint (gdbarch, bp_tgt) != 0)
{
deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp)
{
struct bp_target_info *bp_tgt = bp;
+ struct address_space *aspace = bp_tgt->placed_address_space;
+ CORE_ADDR address = bp_tgt->reqstd_address;
+ struct bp_location *bl;
int ret;
- ret = target_remove_breakpoint (gdbarch, bp_tgt);
+ bl = find_non_raw_software_breakpoint_inserted_here (aspace, address);
+
+ /* Only remove the raw breakpoint if there are no other non-raw
+ breakpoints still inserted at this location. Otherwise, we would
+ be effectively disabling those breakpoints. */
+ if (bl == NULL)
+ ret = target_remove_breakpoint (gdbarch, bp_tgt);
+ else if (!VEC_empty (agent_expr_p, bl->target_info.conditions)
+ || !VEC_empty (agent_expr_p, bl->target_info.tcommands))
+ {
+ /* The target is evaluating conditions, and when we inserted the
+ software single-step breakpoint, we had made the breakpoint
+ unconditional and command-less on the target side. Reinsert
+ to restore the conditions/commands. */
+ ret = target_insert_breakpoint (bl->gdbarch, &bl->target_info);
+ }
+ else
+ ret = 0;
+
xfree (bp_tgt);
return ret;
}
-/* One (or perhaps two) breakpoints used for software single
- stepping. */
-
-static void *single_step_breakpoints[2];
-static struct gdbarch *single_step_gdbarch[2];
-
/* Create and insert a breakpoint for software single step. */
void
single_step_breakpoints[i]);
}
-/* Check whether a software single-step breakpoint is inserted at
- PC. */
+/* Find the software single-step breakpoint that inserted at PC.
+ Returns its slot if found, and -1 if not found. */
static int
-single_step_breakpoint_inserted_here_p (struct address_space *aspace,
- CORE_ADDR pc)
+find_single_step_breakpoint (struct address_space *aspace,
+ CORE_ADDR pc)
{
int i;
struct bp_target_info *bp_tgt = single_step_breakpoints[i];
if (bp_tgt
&& breakpoint_address_match (bp_tgt->placed_address_space,
- bp_tgt->placed_address,
+ bp_tgt->reqstd_address,
aspace, pc))
- return 1;
+ return i;
}
- return 0;
+ return -1;
+}
+
+/* Check whether a software single-step breakpoint is inserted at
+ PC. */
+
+int
+single_step_breakpoint_inserted_here_p (struct address_space *aspace,
+ CORE_ADDR pc)
+{
+ return find_single_step_breakpoint (aspace, pc) >= 0;
}
/* Returns 0 if 'bp' is NOT a syscall catchpoint,
/* Complete syscall names. Used by "catch syscall". */
static VEC (char_ptr) *
catch_syscall_completer (struct cmd_list_element *cmd,
- char *text, char *word)
+ const char *text, const char *word)
{
const char **list = get_syscall_names ();
VEC (char_ptr) *retlist
- = (list == NULL) ? NULL : complete_on_enum (list, text, word);
+ = (list == NULL) ? NULL : complete_on_enum (list, word, word);
xfree (list);
return retlist;
else
ops = &tracepoint_breakpoint_ops;
- if (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))
- set_tracepoint_count (breakpoint_count);
+ 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);
}
static void
ftrace_command (char *arg, int from_tty)
{
- if (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))
- 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. */
else
ops = &tracepoint_breakpoint_ops;
- if (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_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;
}
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);
count = strtoul (args, &args, 10); /* Count comes first, then TP num. */
- while (*args && isspace ((int) *args))
- args++;
-
+ args = skip_spaces (args);
if (*args && strncasecmp (args, "all", 3) == 0)
{
struct breakpoint *b;
}
else if (*args == '\0')
{
- t1 = get_tracepoint_by_number (&args, NULL, 1);
+ t1 = get_tracepoint_by_number (&args, NULL);
if (t1)
trace_pass_set_count (t1, count, from_tty);
}
init_number_or_range (&state, args);
while (!state.finished)
{
- t1 = get_tracepoint_by_number (&args, &state, 1);
+ t1 = get_tracepoint_by_number (&args, &state);
if (t1)
trace_pass_set_count (t1, count, from_tty);
}
/* Utility: parse a tracepoint number and look it up in the list.
If STATE is not NULL, use, get_number_or_range_state and ignore ARG.
- If OPTIONAL_P is true, then if the argument is missing, the most
- recent tracepoint (tracepoint_count) is returned. */
+ If the argument is missing, the most recent tracepoint
+ (tracepoint_count) is returned. */
+
struct tracepoint *
get_tracepoint_by_number (char **arg,
- struct get_number_or_range_state *state,
- int optional_p)
+ struct get_number_or_range_state *state)
{
- extern int tracepoint_count;
struct breakpoint *t;
int tpnum;
char *instring = arg == NULL ? NULL : *arg;
tpnum = get_number_or_range (state);
}
else if (arg == NULL || *arg == NULL || ! **arg)
- {
- if (optional_p)
- tpnum = tracepoint_count;
- else
- error_no_arg (_("tracepoint number"));
- }
+ tpnum = tracepoint_count;
else
tpnum = get_number (arg);
printf_filtered (_("bad tracepoint number at or near '%s'\n"),
instring);
else
- printf_filtered (_("Tracepoint argument missing "
- "and no previous tracepoint\n"));
+ printf_filtered (_("No previous tracepoint\n"));
return NULL;
}
{
struct breakpoint *tp;
int any = 0;
- char *pathname;
struct cleanup *cleanup;
struct ui_file *fp;
int extra_trace_bits = 0;
return;
}
- pathname = tilde_expand (filename);
- cleanup = make_cleanup (xfree, pathname);
- fp = gdb_fopen (pathname, "w");
+ filename = tilde_expand (filename);
+ cleanup = make_cleanup (xfree, filename);
+ fp = gdb_fopen (filename, "w");
if (!fp)
error (_("Unable to open file '%s' for saving (%s)"),
filename, safe_strerror (errno));
if (tp->ignore_count)
fprintf_unfiltered (fp, " ignore $bpnum %d\n", tp->ignore_count);
- if (tp->commands)
+ if (tp->type != bp_dprintf && tp->commands)
{
volatile struct gdb_exception ex;
}
if (tp->enable_state == bp_disabled)
- fprintf_unfiltered (fp, "disable\n");
+ fprintf_unfiltered (fp, "disable $bpnum\n");
/* If this is a multi-location breakpoint, check if the locations
should be individually disabled. Watchpoint locations are
if (extra_trace_bits && *default_collect)
fprintf_unfiltered (fp, "set default-collect %s\n", default_collect);
- do_cleanups (cleanup);
if (from_tty)
printf_filtered (_("Saved to file '%s'.\n"), filename);
+ do_cleanups (cleanup);
}
/* The `save breakpoints' command. */
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\
void
add_catch_command (char *name, char *docstring,
- void (*sfunc) (char *args, int from_tty,
- struct cmd_list_element *command),
+ cmd_sfunc_ftype *sfunc,
completer_ftype *completer,
void *user_data_catch,
void *user_data_tcatch)
{
printf_unfiltered (_("\"save\" must be followed by "
"the name of a save subcommand.\n"));
- help_list (save_cmdlist, "save ", -1, gdb_stdout);
+ help_list (save_cmdlist, "save ", all_commands, gdb_stdout);
}
struct breakpoint *
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->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->print_it = print_it_exception_catchpoint;
- ops->print_one = print_one_exception_catchpoint;
- ops->print_mention = print_mention_exception_catchpoint;
- ops->print_recreate = print_recreate_exception_catchpoint;
-
/* Watchpoints. */
ops = &watchpoint_breakpoint_ops;
*ops = base_breakpoint_ops;
ops->print_it = print_it_watchpoint;
ops->print_mention = print_mention_watchpoint;
ops->print_recreate = print_recreate_watchpoint;
+ ops->explains_signal = explains_signal_watchpoint;
/* Masked watchpoints. */
ops = &masked_watchpoint_breakpoint_ops;
ops = &dprintf_breakpoint_ops;
*ops = bkpt_base_breakpoint_ops;
- ops->re_set = bkpt_re_set;
+ ops->re_set = dprintf_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;
+ ops->print_recreate = dprintf_print_recreate;
+ ops->after_condition_true = dprintf_after_condition_true;
+ ops->breakpoint_hit = dprintf_breakpoint_hit;
}
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+static struct cmd_list_element *enablebreaklist = NULL;
+
void
_initialize_breakpoint (void)
{
initialize_breakpoint_ops ();
observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
+ observer_attach_free_objfile (disable_breakpoints_in_freed_objfile);
observer_attach_inferior_exit (clear_syscall_counts);
observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
= register_objfile_data_with_cleanup (NULL, free_breakpoint_probes);
catch_syscall_inferior_data
- = register_inferior_data_with_cleanup (catch_syscall_inferior_data_cleanup);
+ = 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
&tcatch_cmdlist, "tcatch ",
0/*allow-unknown*/, &cmdlist);
- /* Add catch and tcatch sub-commands. */
- add_catch_command ("catch", _("\
-Catch an exception, when caught."),
- catch_catch_command,
- NULL,
- CATCH_PERMANENT,
- CATCH_TEMPORARY);
- add_catch_command ("throw", _("\
-Catch an exception, when thrown."),
- catch_throw_command,
- NULL,
- CATCH_PERMANENT,
- CATCH_TEMPORARY);
add_catch_command ("fork", _("Catch calls to fork."),
catch_fork_command_1,
NULL,
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_auto_boolean_cmd ("always-inserted", class_support,
- &always_inserted_mode, _("\
+ add_setshow_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\
-resumed, and removed when execution stops. When this mode is on,\n\
-breakpoints are inserted immediately and removed only when the user\n\
-deletes the breakpoint. When this mode is auto (which is the default),\n\
-the behaviour depends on the non-stop setting (see help set non-stop).\n\
-In this case, if gdb is controlling the inferior in non-stop mode, gdb\n\
-behaves as if always-inserted mode is on; if gdb is controlling the\n\
-inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
+When this mode is on, breakpoints are inserted immediately as soon as\n\
+they're created, kept inserted even when execution stops, and removed\n\
+only when the user deletes them. When this mode is off (the default),\n\
+breakpoints are inserted only when execution continues, and removed\n\
+when execution stops."),
NULL,
&show_always_inserted_mode,
&breakpoint_set_cmdlist,
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\
-"));
+If a function is specified, break at start of code for that function."));
set_cmd_completer (c, location_completer);
add_setshow_enum_cmd ("dprintf-style", class_support,
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);
+ observer_attach_thread_exit (remove_threaded_breakpoints);
}