#include "jit.h"
#include "xml-syscall.h"
#include "parser-defs.h"
+#include "gdb_regex.h"
+#include "probe.h"
#include "cli/cli-utils.h"
#include "continuations.h"
#include "stack.h"
#include "skip.h"
-#include "record.h"
#include "gdb_regex.h"
+#include "ax-gdb.h"
/* readline include files */
#include "readline/readline.h"
enum bpdisp, int, int,
int,
const struct breakpoint_ops *,
- int, int, int);
+ int, int, int, unsigned);
static void decode_linespec_default (struct breakpoint *, char **,
struct symtabs_and_lines *);
static int is_masked_watchpoint (const struct breakpoint *b);
+static struct bp_location **get_first_locp_gte_addr (CORE_ADDR address);
+
/* Return 1 if B refers to a static tracepoint set by marker ("-m"), zero
otherwise. */
breakpoints. */
struct breakpoint_ops bkpt_breakpoint_ops;
+/* Breakpoints set on probes. */
+static struct breakpoint_ops bkpt_probe_breakpoint_ops;
+
/* A reference-counted struct command_line. This lets multiple
breakpoints share a single command list. */
struct counted_command_line
int
breakpoints_always_inserted_mode (void)
{
- return ((always_inserted_mode == always_inserted_on
- || (always_inserted_mode == always_inserted_auto && non_stop))
- && !RECORD_IS_USED);
+ return (always_inserted_mode == always_inserted_on
+ || (always_inserted_mode == always_inserted_auto && non_stop));
+}
+
+static const char condition_evaluation_both[] = "host or target";
+
+/* Modes for breakpoint condition evaluation. */
+static const char condition_evaluation_auto[] = "auto";
+static const char condition_evaluation_host[] = "host";
+static const char condition_evaluation_target[] = "target";
+static const char *const condition_evaluation_enums[] = {
+ condition_evaluation_auto,
+ condition_evaluation_host,
+ condition_evaluation_target,
+ NULL
+};
+
+/* Global that holds the current mode for breakpoint condition evaluation. */
+static const char *condition_evaluation_mode_1 = condition_evaluation_auto;
+
+/* Global that we use to display information to the user (gets its value from
+ condition_evaluation_mode_1. */
+static const char *condition_evaluation_mode = condition_evaluation_auto;
+
+/* Translate a condition evaluation mode MODE into either "host"
+ or "target". This is used mostly to translate from "auto" to the
+ real setting that is being used. It returns the translated
+ evaluation mode. */
+
+static const char *
+translate_condition_evaluation_mode (const char *mode)
+{
+ if (mode == condition_evaluation_auto)
+ {
+ if (target_supports_evaluation_of_breakpoint_conditions ())
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_host;
+ }
+ else
+ return mode;
+}
+
+/* Discovers what condition_evaluation_auto translates to. */
+
+static const char *
+breakpoint_condition_evaluation_mode (void)
+{
+ return translate_condition_evaluation_mode (condition_evaluation_mode);
+}
+
+/* Return true if GDB should evaluate breakpoint conditions or false
+ otherwise. */
+
+static int
+gdb_evaluates_breakpoint_condition_p (void)
+{
+ const char *mode = breakpoint_condition_evaluation_mode ();
+
+ return (mode == condition_evaluation_host);
}
void _initialize_breakpoint (void);
BP_TMP < bp_location + bp_location_count && (B = *BP_TMP); \
BP_TMP++)
+/* Iterates through locations with address ADDRESS for the currently selected
+ program space. BP_LOCP_TMP points to each object. BP_LOCP_START points
+ to where the loop should start from.
+ If BP_LOCP_START is a NULL pointer, the macro automatically seeks the
+ appropriate location to start with. */
+
+#define ALL_BP_LOCATIONS_AT_ADDR(BP_LOCP_TMP, BP_LOCP_START, ADDRESS) \
+ for (BP_LOCP_START = BP_LOCP_START == NULL ? get_first_locp_gte_addr (ADDRESS) : BP_LOCP_START, \
+ BP_LOCP_TMP = BP_LOCP_START; \
+ BP_LOCP_START \
+ && (BP_LOCP_TMP < bp_location + bp_location_count \
+ && (*BP_LOCP_TMP)->address == ADDRESS); \
+ BP_LOCP_TMP++)
+
/* Iterator for tracepoints only. */
#define ALL_TRACEPOINTS(B) \
\f
+/* Mark locations as "conditions have changed" in case the target supports
+ evaluating conditions on its side. */
+
+static void
+mark_breakpoint_modified (struct breakpoint *b)
+{
+ struct bp_location *loc;
+
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return;
+
+ if (!is_breakpoint (b))
+ return;
+
+ for (loc = b->loc; loc; loc = loc->next)
+ loc->condition_changed = condition_modified;
+}
+
+/* Mark location as "conditions have changed" in case the target supports
+ evaluating conditions on its side. */
+
+static void
+mark_breakpoint_location_modified (struct bp_location *loc)
+{
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+
+ return;
+
+ if (!is_breakpoint (loc->owner))
+ return;
+
+ loc->condition_changed = condition_modified;
+}
+
+/* Sets the condition-evaluation mode using the static global
+ condition_evaluation_mode. */
+
+static void
+set_condition_evaluation_mode (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct breakpoint *b;
+ const char *old_mode, *new_mode;
+
+ if ((condition_evaluation_mode_1 == condition_evaluation_target)
+ && !target_supports_evaluation_of_breakpoint_conditions ())
+ {
+ condition_evaluation_mode_1 = condition_evaluation_mode;
+ warning (_("Target does not support breakpoint condition evaluation.\n"
+ "Using host evaluation mode instead."));
+ return;
+ }
+
+ new_mode = translate_condition_evaluation_mode (condition_evaluation_mode_1);
+ old_mode = translate_condition_evaluation_mode (condition_evaluation_mode);
+
+ /* Flip the switch. Flip it even if OLD_MODE == NEW_MODE as one of the
+ settings was "auto". */
+ condition_evaluation_mode = condition_evaluation_mode_1;
+
+ /* Only update the mode if the user picked a different one. */
+ if (new_mode != old_mode)
+ {
+ struct bp_location *loc, **loc_tmp;
+ /* If the user switched to a different evaluation mode, we
+ need to synch the changes with the target as follows:
+
+ "host" -> "target": Send all (valid) conditions to the target.
+ "target" -> "host": Remove all the conditions from the target.
+ */
+
+ if (new_mode == condition_evaluation_target)
+ {
+ /* Mark everything modified and synch conditions with the
+ target. */
+ ALL_BP_LOCATIONS (loc, loc_tmp)
+ mark_breakpoint_location_modified (loc);
+ }
+ else
+ {
+ /* Manually mark non-duplicate locations to synch conditions
+ with the target. We do this to remove all the conditions the
+ target knows about. */
+ ALL_BP_LOCATIONS (loc, loc_tmp)
+ if (is_breakpoint (loc->owner) && loc->inserted)
+ loc->needs_update = 1;
+ }
+
+ /* Do the update. */
+ update_global_location_list (1);
+ }
+
+ return;
+}
+
+/* Shows the current mode of breakpoint condition evaluation. Explicitly shows
+ what "auto" is translating to. */
+
+static void
+show_condition_evaluation_mode (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ if (condition_evaluation_mode == condition_evaluation_auto)
+ fprintf_filtered (file,
+ _("Breakpoint condition evaluation "
+ "mode is %s (currently %s).\n"),
+ value,
+ breakpoint_condition_evaluation_mode ());
+ else
+ fprintf_filtered (file, _("Breakpoint condition evaluation mode is %s.\n"),
+ value);
+}
+
+/* A comparison function for bp_location AP and BP that is used by
+ bsearch. This comparison function only cares about addresses, unlike
+ the more general bp_location_compare function. */
+
+static int
+bp_location_compare_addrs (const void *ap, const void *bp)
+{
+ struct bp_location *a = *(void **) ap;
+ struct bp_location *b = *(void **) bp;
+
+ if (a->address == b->address)
+ return 0;
+ else
+ return ((a->address > b->address) - (a->address < b->address));
+}
+
+/* Helper function to skip all bp_locations with addresses
+ less than ADDRESS. It returns the first bp_location that
+ is greater than or equal to ADDRESS. If none is found, just
+ return NULL. */
+
+static struct bp_location **
+get_first_locp_gte_addr (CORE_ADDR address)
+{
+ struct bp_location dummy_loc;
+ struct bp_location *dummy_locp = &dummy_loc;
+ struct bp_location **locp_found = NULL;
+
+ /* Initialize the dummy location's address field. */
+ memset (&dummy_loc, 0, sizeof (struct bp_location));
+ dummy_loc.address = address;
+
+ /* Find a close match to the first location at ADDRESS. */
+ locp_found = bsearch (&dummy_locp, bp_location, bp_location_count,
+ sizeof (struct bp_location **),
+ bp_location_compare_addrs);
+
+ /* Nothing was found, nothing left to do. */
+ if (locp_found == NULL)
+ return NULL;
+
+ /* We may have found a location that is at ADDRESS but is not the first in the
+ location's list. Go backwards (if possible) and locate the first one. */
+ while ((locp_found - 1) >= bp_location
+ && (*(locp_found - 1))->address == address)
+ locp_found--;
+
+ return locp_found;
+}
+
void
set_breakpoint_condition (struct breakpoint *b, char *exp,
int from_tty)
{
xfree (loc->cond);
loc->cond = NULL;
+
+ /* No need to free the condition agent expression
+ bytecode (if we have one). We will handle this
+ when we go through update_global_location_list. */
}
}
}
}
}
+ mark_breakpoint_modified (b);
+
breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
error (_("Cannot set a condition where a Python 'stop' "
"method has been defined in the breakpoint."));
set_breakpoint_condition (b, p, from_tty);
+
+ if (is_breakpoint (b))
+ update_global_location_list (1);
+
return;
}
/* Update BUF, which is LEN bytes read from the target address MEMADDR,
by replacing any memory breakpoints with their shadowed contents.
+ If READBUF is not NULL, this buffer must not overlap with any of
+ the breakpoint location's shadow_contents buffers. Otherwise,
+ a failed assertion internal error will be raised.
+
The range of shadowed area by each bp_location is:
bl->address - bp_location_placed_address_before_address_max
up to bl->address + bp_location_shadow_len_after_address_max
if (readbuf != NULL)
{
+ /* Verify that the readbuf buffer does not overlap with
+ the shadow_contents buffer. */
+ gdb_assert (bl->target_info.shadow_contents >= readbuf + len
+ || readbuf >= (bl->target_info.shadow_contents
+ + bl->target_info.shadow_len));
+
/* Update the read buffer with this inserted breakpoint's
shadow. */
memcpy (readbuf + bp_addr - memaddr,
}
\f
+/* Return true if BPT is either a software breakpoint or a hardware
+ breakpoint. */
+
+int
+is_breakpoint (const struct breakpoint *bpt)
+{
+ return (bpt->type == bp_breakpoint
+ || bpt->type == bp_hardware_breakpoint);
+}
+
/* Return true if BPT is of any hardware watchpoint kind. */
static int
return result;
}
+/* Parses a conditional described by an expression COND into an
+ agent expression bytecode suitable for evaluation
+ by the bytecode interpreter. Return NULL if there was
+ any error during parsing. */
+
+static struct agent_expr *
+parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond)
+{
+ struct agent_expr *aexpr = NULL;
+ struct cleanup *old_chain = NULL;
+ volatile struct gdb_exception ex;
+
+ if (!cond)
+ return NULL;
+
+ /* We don't want to stop processing, so catch any errors
+ that may show up. */
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ aexpr = gen_eval_for_expr (scope, cond);
+ }
+
+ if (ex.reason < 0)
+ {
+ /* If we got here, it means the condition could not be parsed to a valid
+ bytecode expression and thus can't be evaluated on the target's side.
+ It's no use iterating through the conditions. */
+ return NULL;
+ }
+
+ /* We have a valid agent expression. */
+ return aexpr;
+}
+
+/* Based on location BL, create a list of breakpoint conditions to be
+ passed on to the target. If we have duplicated locations with different
+ conditions, we will add such conditions to the list. The idea is that the
+ target will evaluate the list of conditions and will only notify GDB when
+ one of them is true. */
+
+static void
+build_target_condition_list (struct bp_location *bl)
+{
+ struct bp_location **locp = NULL, **loc2p;
+ int null_condition_or_parse_error = 0;
+ int modified = bl->needs_update;
+ struct bp_location *loc;
+
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return;
+
+ /* Do a first pass to check for locations with no assigned
+ conditions or conditions that fail to parse to a valid agent expression
+ bytecode. If any of these happen, then it's no use to send conditions
+ to the target since this location will always trigger and generate a
+ response back to GDB. */
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+ {
+ loc = (*loc2p);
+ if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
+ {
+ if (modified)
+ {
+ struct agent_expr *aexpr;
+
+ /* Re-parse the conditions since something changed. In that
+ case we already freed the condition bytecodes (see
+ force_breakpoint_reinsertion). We just
+ need to parse the condition to bytecodes again. */
+ aexpr = parse_cond_to_aexpr (bl->address, loc->cond);
+ loc->cond_bytecode = aexpr;
+
+ /* Check if we managed to parse the conditional expression
+ correctly. If not, we will not send this condition
+ to the target. */
+ if (aexpr)
+ continue;
+ }
+
+ /* If we have a NULL bytecode expression, it means something
+ went wrong or we have a null condition expression. */
+ if (!loc->cond_bytecode)
+ {
+ null_condition_or_parse_error = 1;
+ break;
+ }
+ }
+ }
+
+ /* If any of these happened, it means we will have to evaluate the conditions
+ for the location's address on gdb's side. It is no use keeping bytecodes
+ for all the other duplicate locations, thus we free all of them here.
+
+ This is so we have a finer control over which locations' conditions are
+ being evaluated by GDB or the remote stub. */
+ if (null_condition_or_parse_error)
+ {
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+ {
+ loc = (*loc2p);
+ if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
+ {
+ /* Only go as far as the first NULL bytecode is
+ located. */
+ if (!loc->cond_bytecode)
+ return;
+
+ free_agent_expr (loc->cond_bytecode);
+ loc->cond_bytecode = NULL;
+ }
+ }
+ }
+
+ /* No NULL conditions or failed bytecode generation. Build a condition list
+ for this location's address. */
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+ {
+ loc = (*loc2p);
+ if (loc->cond
+ && is_breakpoint (loc->owner)
+ && loc->pspace->num == bl->pspace->num
+ && loc->owner->enable_state == bp_enabled
+ && loc->enabled)
+ /* Add the condition to the vector. This will be used later to send the
+ conditions to the target. */
+ VEC_safe_push (agent_expr_p, bl->target_info.conditions,
+ loc->cond_bytecode);
+ }
+
+ return;
+}
+
/* 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.
{
int val = 0;
- if (!should_be_inserted (bl) || bl->inserted)
+ if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
return 0;
- /* Initialize the target-specific information. */
- memset (&bl->target_info, 0, sizeof (bl->target_info));
+ /* Note we don't initialize bl->target_info, as that wipes out
+ the breakpoint location's shadow_contents if the breakpoint
+ is still inserted at that location. This in turn breaks
+ target_read_memory which depends on these buffers when
+ a memory read is requested at the breakpoint location:
+ Once the target_info has been wiped, we fail to see that
+ we have a breakpoint inserted at that address and thus
+ read the breakpoint instead of returning the data saved in
+ the breakpoint location's shadow contents. */
bl->target_info.placed_address = bl->address;
bl->target_info.placed_address_space = bl->pspace->aspace;
bl->target_info.length = bl->length;
+ /* When working with target-side conditions, we must pass all the conditions
+ for the same breakpoint address down to the target since GDB will not
+ insert those locations. With a list of breakpoint conditions, the target
+ can decide when to stop and notify GDB. */
+
+ if (is_breakpoint (bl->owner))
+ {
+ build_target_condition_list (bl);
+ /* Reset the condition modification marker. */
+ bl->needs_update = 0;
+ }
+
if (bl->loc_type == bp_loc_software_breakpoint
|| bl->loc_type == bp_loc_hardware_breakpoint)
{
insert_breakpoint_locations ();
}
+/* Invoke CALLBACK for each of bp_location. */
+
+void
+iterate_over_bp_locations (walk_bp_location_callback callback)
+{
+ struct bp_location *loc, **loc_tmp;
+
+ ALL_BP_LOCATIONS (loc, loc_tmp)
+ {
+ callback (loc, NULL);
+ }
+}
+
+/* This is used when we need to synch breakpoint conditions between GDB and the
+ target. It is the case with deleting and disabling of breakpoints when using
+ always-inserted mode. */
+
+static void
+update_inserted_breakpoint_locations (void)
+{
+ struct bp_location *bl, **blp_tmp;
+ int error_flag = 0;
+ int val = 0;
+ int disabled_breaks = 0;
+ int hw_breakpoint_error = 0;
+
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
+
+ /* Explicitly mark the warning -- this will only be printed if
+ there was an error. */
+ fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+ save_current_space_and_thread ();
+
+ ALL_BP_LOCATIONS (bl, blp_tmp)
+ {
+ /* We only want to update software breakpoints and hardware
+ breakpoints. */
+ if (!is_breakpoint (bl->owner))
+ continue;
+
+ /* We only want to update locations that are already inserted
+ and need updating. This is to avoid unwanted insertion during
+ deletion of breakpoints. */
+ if (!bl->inserted || (bl->inserted && !bl->needs_update))
+ continue;
+
+ switch_to_program_space_and_thread (bl->pspace);
+
+ /* For targets that support global breakpoints, there's no need
+ to select an inferior to insert breakpoint to. In fact, even
+ if we aren't attached to any process yet, we should still
+ insert breakpoints. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch)
+ && ptid_equal (inferior_ptid, null_ptid))
+ continue;
+
+ val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks,
+ &hw_breakpoint_error);
+ if (val)
+ error_flag = val;
+ }
+
+ if (error_flag)
+ {
+ target_terminal_ours_for_output ();
+ error_stream (tmp_error_stream);
+ }
+
+ do_cleanups (cleanups);
+}
+
/* Used when starting or continuing the program. */
static void
ALL_BP_LOCATIONS (bl, blp_tmp)
{
- if (!should_be_inserted (bl) || bl->inserted)
+ if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
continue;
/* There is no point inserting thread-specific breakpoints if
/* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
+ /* True if we have looked for longjmp probes. */
+ int longjmp_searched;
+
+ /* SystemTap probe points for longjmp (if any). */
+ VEC (probe_p) *longjmp_probes;
+
/* Minimal symbol for "std::terminate()" (if any). */
struct minimal_symbol *terminate_msym;
/* Minimal symbol for "_Unwind_DebugHook" (if any). */
struct minimal_symbol *exception_msym;
+
+ /* True if we have looked for exception probes. */
+ int exception_searched;
+
+ /* SystemTap probe points for unwinding (if any). */
+ VEC (probe_p) *exception_probes;
};
static const struct objfile_data *breakpoint_objfile_key;
return bp_objfile_data;
}
+static void
+free_breakpoint_probes (struct objfile *obj, void *data)
+{
+ struct breakpoint_objfile_data *bp_objfile_data = data;
+
+ VEC_free (probe_p, bp_objfile_data->longjmp_probes);
+ VEC_free (probe_p, bp_objfile_data->exception_probes);
+}
+
static void
create_overlay_event_breakpoint (void)
{
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ if (!bp_objfile_data->longjmp_searched)
+ {
+ bp_objfile_data->longjmp_probes
+ = find_probes_in_objfile (objfile, "libc", "longjmp");
+ bp_objfile_data->longjmp_searched = 1;
+ }
+
+ if (bp_objfile_data->longjmp_probes != NULL)
+ {
+ int i;
+ struct probe *probe;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ for (i = 0;
+ VEC_iterate (probe_p,
+ bp_objfile_data->longjmp_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_longjmp_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-probe-stap libc:longjmp");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
for (i = 0; i < NUM_LONGJMP_NAMES; i++)
{
struct breakpoint *b;
/* Install a master breakpoint on the unwinder's debug hook. */
-void
+static void
create_exception_master_breakpoint (void)
{
struct objfile *objfile;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ /* We prefer the SystemTap probe point if it exists. */
+ if (!bp_objfile_data->exception_searched)
+ {
+ bp_objfile_data->exception_probes
+ = find_probes_in_objfile (objfile, "libgcc", "unwind");
+ bp_objfile_data->exception_searched = 1;
+ }
+
+ if (bp_objfile_data->exception_probes != NULL)
+ {
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ int i;
+ struct probe *probe;
+
+ for (i = 0;
+ VEC_iterate (probe_p,
+ bp_objfile_data->exception_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_exception_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-probe-stap libgcc:unwind");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
+ /* Otherwise, try the hook function. */
+
if (msym_not_found_p (bp_objfile_data->exception_msym))
continue;
(gdb) tar rem :9999 # remote Windows gdbserver.
*/
+ case bp_step_resume:
+
+ /* Also remove step-resume breakpoints. */
+
delete_breakpoint (b);
break;
in breakpoint.h. */
int
-ep_is_catchpoint (struct breakpoint *ep)
+is_catchpoint (struct breakpoint *ep)
{
return (ep->type == bp_catchpoint);
}
b = bs->breakpoint_at;
gdb_assert (b != NULL);
+ /* Even if the target evaluated the condition on its end and notified GDB, we
+ need to do so again since GDB does not know if we stopped due to a
+ breakpoint or a single step breakpoint. */
+
if (frame_id_p (b->frame_id)
&& !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ())))
bs->stop = 0;
return NULL;
}
+/* Determine if the locations of this breakpoint will have their conditions
+ evaluated by the target, host or a mix of both. Returns the following:
+
+ "host": Host evals condition.
+ "host or target": Host or Target evals condition.
+ "target": Target evals condition.
+*/
+
+static const char *
+bp_condition_evaluator (struct breakpoint *b)
+{
+ struct bp_location *bl;
+ char host_evals = 0;
+ char target_evals = 0;
+
+ if (!b)
+ return NULL;
+
+ if (!is_breakpoint (b))
+ return NULL;
+
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return condition_evaluation_host;
+
+ for (bl = b->loc; bl; bl = bl->next)
+ {
+ if (bl->cond_bytecode)
+ target_evals++;
+ else
+ host_evals++;
+ }
+
+ if (host_evals && target_evals)
+ return condition_evaluation_both;
+ else if (target_evals)
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_host;
+}
+
+/* Determine the breakpoint location's condition evaluator. This is
+ similar to bp_condition_evaluator, but for locations. */
+
+static const char *
+bp_location_condition_evaluator (struct bp_location *bl)
+{
+ if (bl && !is_breakpoint (bl->owner))
+ return NULL;
+
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return condition_evaluation_host;
+
+ if (bl && bl->cond_bytecode)
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_host;
+}
+
/* Print the LOC location out of the list of B->LOC locations. */
static void
}
else if (loc)
{
- struct ui_stream *stb = ui_out_stream_new (uiout);
- struct cleanup *stb_chain = make_cleanup_ui_out_stream_delete (stb);
+ struct ui_file *stb = mem_fileopen ();
+ struct cleanup *stb_chain = make_cleanup_ui_file_delete (stb);
- print_address_symbolic (loc->gdbarch, loc->address, stb->stream,
+ print_address_symbolic (loc->gdbarch, loc->address, stb,
demangle, "");
ui_out_field_stream (uiout, "at", stb);
else
ui_out_field_string (uiout, "pending", b->addr_string);
+ if (loc && is_breakpoint (b)
+ && breakpoint_condition_evaluation_mode () == condition_evaluation_target
+ && bp_condition_evaluator (b) == condition_evaluation_both)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "evaluated-by",
+ bp_location_condition_evaluator (loc));
+ ui_out_text (uiout, ")");
+ }
+
do_cleanups (old_chain);
}
else
ui_out_text (uiout, "\tstop only if ");
ui_out_field_string (uiout, "cond", b->cond_string);
+
+ /* Print whether the target is doing the breakpoint's condition
+ evaluation. If GDB is doing the evaluation, don't print anything. */
+ if (is_breakpoint (b)
+ && breakpoint_condition_evaluation_mode ()
+ == condition_evaluation_target)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "evaluated-by",
+ bp_condition_evaluator (b));
+ ui_out_text (uiout, " evals)");
+ }
ui_out_text (uiout, "\n");
}
if (!part_of_multiple && b->hit_count)
{
/* FIXME should make an annotation for this. */
- if (ep_is_catchpoint (b))
+ if (is_catchpoint (b))
ui_out_text (uiout, "\tcatchpoint");
else if (is_tracepoint (b))
ui_out_text (uiout, "\ttracepoint");
loc->ops = ops;
loc->owner = owner;
loc->cond = NULL;
+ loc->cond_bytecode = NULL;
loc->shlib_disabled = 0;
loc->enabled = 1;
case bp_gnu_ifunc_resolver:
case bp_gnu_ifunc_resolver_return:
loc->loc_type = bp_loc_software_breakpoint;
+ mark_breakpoint_location_modified (loc);
break;
case bp_hardware_breakpoint:
loc->loc_type = bp_loc_hardware_breakpoint;
+ mark_breakpoint_location_modified (loc);
break;
case bp_hardware_watchpoint:
case bp_read_watchpoint:
}
}
+void
+delete_longjmp_breakpoint_at_next_stop (int thread)
+{
+ struct breakpoint *b, *b_tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, b_tmp)
+ if (b->type == bp_longjmp || b->type == bp_exception)
+ {
+ if (b->thread == thread)
+ b->disposition = disp_del_at_next_stop;
+ }
+}
+
void
enable_overlay_breakpoints (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
base_breakpoint_ops.dtor (b);
}
+static const struct inferior_data *catch_syscall_inferior_data = NULL;
+
+struct catch_syscall_inferior_data
+{
+ /* We keep a count of the number of times the user has requested a
+ particular syscall to be tracked, and pass this information to the
+ target. This lets capable targets implement filtering directly. */
+
+ /* Number of times that "any" syscall is requested. */
+ int any_syscall_count;
+
+ /* Count of each system call. */
+ VEC(int) *syscalls_counts;
+
+ /* This counts all syscall catch requests, so we can readily determine
+ if any catching is necessary. */
+ int total_syscalls_count;
+};
+
+static struct catch_syscall_inferior_data*
+get_catch_syscall_inferior_data (struct inferior *inf)
+{
+ struct catch_syscall_inferior_data *inf_data;
+
+ inf_data = inferior_data (inf, catch_syscall_inferior_data);
+ if (inf_data == NULL)
+ {
+ inf_data = XZALLOC (struct catch_syscall_inferior_data);
+ set_inferior_data (inf, catch_syscall_inferior_data, inf_data);
+ }
+
+ return inf_data;
+}
+
+static void
+catch_syscall_inferior_data_cleanup (struct inferior *inf, void *arg)
+{
+ xfree (arg);
+}
+
+
/* Implement the "insert" breakpoint_ops method for syscall
catchpoints. */
{
struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
struct inferior *inf = current_inferior ();
+ struct catch_syscall_inferior_data *inf_data
+ = get_catch_syscall_inferior_data (inf);
- ++inf->total_syscalls_count;
+ ++inf_data->total_syscalls_count;
if (!c->syscalls_to_be_caught)
- ++inf->any_syscall_count;
+ ++inf_data->any_syscall_count;
else
{
int i, iter;
{
int elem;
- if (iter >= VEC_length (int, inf->syscalls_counts))
+ if (iter >= VEC_length (int, inf_data->syscalls_counts))
{
- int old_size = VEC_length (int, inf->syscalls_counts);
+ int old_size = VEC_length (int, inf_data->syscalls_counts);
uintptr_t vec_addr_offset
= old_size * ((uintptr_t) sizeof (int));
uintptr_t vec_addr;
- VEC_safe_grow (int, inf->syscalls_counts, iter + 1);
- vec_addr = (uintptr_t) VEC_address (int, inf->syscalls_counts) +
- vec_addr_offset;
+ VEC_safe_grow (int, inf_data->syscalls_counts, iter + 1);
+ vec_addr = ((uintptr_t) VEC_address (int,
+ inf_data->syscalls_counts)
+ + vec_addr_offset);
memset ((void *) vec_addr, 0,
(iter + 1 - old_size) * sizeof (int));
}
- elem = VEC_index (int, inf->syscalls_counts, iter);
- VEC_replace (int, inf->syscalls_counts, iter, ++elem);
+ elem = VEC_index (int, inf_data->syscalls_counts, iter);
+ VEC_replace (int, inf_data->syscalls_counts, iter, ++elem);
}
}
return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
- inf->total_syscalls_count != 0,
- inf->any_syscall_count,
- VEC_length (int, inf->syscalls_counts),
- VEC_address (int, inf->syscalls_counts));
+ inf_data->total_syscalls_count != 0,
+ inf_data->any_syscall_count,
+ VEC_length (int,
+ inf_data->syscalls_counts),
+ VEC_address (int,
+ inf_data->syscalls_counts));
}
/* Implement the "remove" breakpoint_ops method for syscall
{
struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
struct inferior *inf = current_inferior ();
+ struct catch_syscall_inferior_data *inf_data
+ = get_catch_syscall_inferior_data (inf);
- --inf->total_syscalls_count;
+ --inf_data->total_syscalls_count;
if (!c->syscalls_to_be_caught)
- --inf->any_syscall_count;
+ --inf_data->any_syscall_count;
else
{
int i, iter;
i++)
{
int elem;
- if (iter >= VEC_length (int, inf->syscalls_counts))
+ if (iter >= VEC_length (int, inf_data->syscalls_counts))
/* Shouldn't happen. */
continue;
- elem = VEC_index (int, inf->syscalls_counts, iter);
- VEC_replace (int, inf->syscalls_counts, iter, --elem);
+ elem = VEC_index (int, inf_data->syscalls_counts, iter);
+ VEC_replace (int, inf_data->syscalls_counts, iter, --elem);
}
}
return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
- inf->total_syscalls_count != 0,
- inf->any_syscall_count,
- VEC_length (int, inf->syscalls_counts),
+ inf_data->total_syscalls_count != 0,
+ inf_data->any_syscall_count,
+ VEC_length (int,
+ inf_data->syscalls_counts),
VEC_address (int,
- inf->syscalls_counts));
+ inf_data->syscalls_counts));
}
/* Implement the "breakpoint_hit" breakpoint_ops method for syscall
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
+ copy->loc->probe = orig->loc->probe;
if (orig->loc->source_file != NULL)
copy->loc->source_file = xstrdup (orig->loc->source_file);
loc->requested_address = sal->pc;
loc->address = adjusted_address;
loc->pspace = sal->pspace;
+ loc->probe = sal->probe;
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
loc->gdbarch = loc_gdbarch;
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
- int enabled, int internal, int display_canonical)
+ int enabled, int internal, unsigned flags,
+ int display_canonical)
{
int i;
b->enable_state = enabled ? bp_enabled : bp_disabled;
b->disposition = disposition;
+ if ((flags & CREATE_BREAKPOINT_FLAGS_INSERTED) != 0)
+ b->loc->inserted = 1;
+
if (type == bp_static_tracepoint)
{
struct tracepoint *t = (struct tracepoint *) b;
else
{
loc = add_location_to_breakpoint (b, &sal);
+ if ((flags & CREATE_BREAKPOINT_FLAGS_INSERTED) != 0)
+ loc->inserted = 1;
}
if (bp_loc_is_permanent (loc))
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
- int enabled, int internal, int display_canonical)
+ int enabled, int internal, unsigned flags,
+ int display_canonical)
{
struct breakpoint *b;
struct cleanup *old_chain;
type, disposition,
thread, task, ignore_count,
ops, from_tty,
- enabled, internal, display_canonical);
+ enabled, internal, flags,
+ display_canonical);
discard_cleanups (old_chain);
install_breakpoint (internal, b, 0);
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
- int enabled, int internal)
+ int enabled, int internal, unsigned flags)
{
int i;
struct linespec_sals *lsal;
filter_string,
cond_string, type, disposition,
thread, task, ignore_count, ops,
- from_tty, enabled, internal,
+ from_tty, enabled, internal, flags,
canonical->special_display);
discard_cleanups (inner);
}
int ignore_count,
enum auto_boolean pending_break_support,
const struct breakpoint_ops *ops,
- int from_tty, int enabled, int internal)
+ int from_tty, int enabled, int internal,
+ unsigned flags)
{
volatile struct gdb_exception e;
char *copy_arg = NULL;
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
- from_tty, enabled, internal);
+ from_tty, enabled, internal, flags);
}
else
{
enum bptype type_wanted = (flag & BP_HARDWAREFLAG
? bp_hardware_breakpoint
: bp_breakpoint);
+ struct breakpoint_ops *ops;
+ const char *arg_cp = arg;
+
+ /* Matching breakpoints on probes. */
+ if (arg && probe_linespec_to_ops (&arg_cp) != NULL)
+ ops = &bkpt_probe_breakpoint_ops;
+ else
+ ops = &bkpt_breakpoint_ops;
create_breakpoint (get_current_arch (),
arg,
tempflag, type_wanted,
0 /* Ignore count */,
pending_break_support,
- &bkpt_breakpoint_ops,
+ ops,
from_tty,
1 /* enabled */,
- 0 /* internal */);
+ 0 /* internal */,
+ 0);
}
/* Helper function for break_command_1 and disassemble_command. */
{
CORE_ADDR address_start, address_end;
struct bp_location *bl = b->loc;
- struct ui_stream *stb = ui_out_stream_new (uiout);
- struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
+ struct ui_file *stb = mem_fileopen ();
+ struct cleanup *cleanup = make_cleanup_ui_file_delete (stb);
gdb_assert (bl);
address_end = address_start + bl->length - 1;
ui_out_text (uiout, "\taddress range: ");
- fprintf_unfiltered (stb->stream, "[%s, %s]",
+ fprintf_unfiltered (stb, "[%s, %s]",
print_core_address (bl->gdbarch, address_start),
print_core_address (bl->gdbarch, address_end));
ui_out_field_stream (uiout, "addr", stb);
means EXP is variable. Also the constant detection may fail for
some constant expressions and in such case still falsely return
zero. */
+
static int
watchpoint_exp_is_const (const struct expression *exp)
{
case UNOP_COMPLEMENT:
case UNOP_ADDR:
case UNOP_HIGH:
+ case UNOP_CAST:
/* Unary, binary and ternary operators: We have to check
their operands. If they are constant, then so is the
result of that operation. For instance, if A and B are
struct cleanup *old_chain;
struct breakpoint *b;
const struct bp_location *bl;
- struct ui_stream *stb;
+ struct ui_file *stb;
enum print_stop_action result;
struct watchpoint *w;
struct ui_out *uiout = current_uiout;
b = bs->breakpoint_at;
w = (struct watchpoint *) b;
- stb = ui_out_stream_new (uiout);
- old_chain = make_cleanup_ui_out_stream_delete (stb);
+ stb = mem_fileopen ();
+ old_chain = make_cleanup_ui_file_delete (stb);
switch (b->type)
{
mention (b);
make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nOld value = ");
- watchpoint_value_print (bs->old_val, stb->stream);
+ watchpoint_value_print (bs->old_val, stb);
ui_out_field_stream (uiout, "old", stb);
ui_out_text (uiout, "\nNew value = ");
- watchpoint_value_print (w->val, stb->stream);
+ watchpoint_value_print (w->val, stb);
ui_out_field_stream (uiout, "new", stb);
ui_out_text (uiout, "\n");
/* More than one watchpoint may have been triggered. */
mention (b);
make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
- watchpoint_value_print (w->val, stb->stream);
+ watchpoint_value_print (w->val, stb);
ui_out_field_stream (uiout, "value", stb);
ui_out_text (uiout, "\n");
result = PRINT_UNKNOWN;
mention (b);
make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nOld value = ");
- watchpoint_value_print (bs->old_val, stb->stream);
+ watchpoint_value_print (bs->old_val, stb);
ui_out_field_stream (uiout, "old", stb);
ui_out_text (uiout, "\nNew value = ");
}
make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
}
- watchpoint_value_print (w->val, stb->stream);
+ watchpoint_value_print (w->val, stb);
ui_out_field_stream (uiout, "new", stb);
ui_out_text (uiout, "\n");
result = PRINT_UNKNOWN;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct frame_info *frame = get_selected_frame (NULL);
+ struct gdbarch *frame_gdbarch = get_frame_arch (frame);
+ struct frame_id stack_frame_id = get_stack_frame_id (frame);
+ struct frame_id caller_frame_id = frame_unwind_caller_id (frame);
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2 = NULL;
struct cleanup *old_chain;
resolve_sal_pc (&sal);
- if (anywhere)
- /* If the user told us to continue until a specified location,
- we don't specify a frame at which we need to stop. */
- breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
- null_frame_id, bp_until);
- else
- /* Otherwise, specify the selected frame, because we want to stop
- only at the very same frame. */
- breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
- get_stack_frame_id (frame),
- bp_until);
-
- old_chain = make_cleanup_delete_breakpoint (breakpoint);
-
tp = inferior_thread ();
thread = tp->num;
+ old_chain = make_cleanup (null_cleanup, NULL);
+
+ /* Installing a breakpoint invalidates the frame chain (as it may
+ need to switch threads), so do any frame handling first. */
+
/* Keep within the current frame, or in frames called by the current
one. */
- if (frame_id_p (frame_unwind_caller_id (frame)))
+ if (frame_id_p (caller_frame_id))
{
- sal = find_pc_line (frame_unwind_caller_pc (frame), 0);
- sal.pc = frame_unwind_caller_pc (frame);
+ struct symtab_and_line sal2;
+
+ sal2 = find_pc_line (frame_unwind_caller_pc (frame), 0);
+ sal2.pc = frame_unwind_caller_pc (frame);
breakpoint2 = set_momentary_breakpoint (frame_unwind_caller_arch (frame),
- sal,
- frame_unwind_caller_id (frame),
+ sal2,
+ caller_frame_id,
bp_until);
make_cleanup_delete_breakpoint (breakpoint2);
- set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame));
+ set_longjmp_breakpoint (tp, caller_frame_id);
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
}
+ /* set_momentary_breakpoint could invalidate FRAME. */
+ frame = NULL;
+
+ if (anywhere)
+ /* If the user told us to continue until a specified location,
+ we don't specify a frame at which we need to stop. */
+ breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
+ null_frame_id, bp_until);
+ else
+ /* Otherwise, specify the selected frame, because we want to stop
+ only at the very same frame. */
+ breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
+ stack_frame_id, bp_until);
+ make_cleanup_delete_breakpoint (breakpoint);
+
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
/* If we are running asynchronously, and proceed call above has
AUTO_BOOLEAN_TRUE /* pending */,
&gnu_v3_exception_catchpoint_ops, from_tty,
1 /* enabled */,
- 0 /* internal */);
+ 0 /* internal */,
+ 0);
return 1;
}
if (a->address != b->address)
return (a->address > b->address) - (a->address < b->address);
+ /* Sort locations at the same address by their pspace number, keeping
+ locations of the same inferior (in a multi-inferior environment)
+ grouped. */
+
+ if (a->pspace->num != b->pspace->num)
+ return ((a->pspace->num > b->pspace->num)
+ - (a->pspace->num < b->pspace->num));
+
/* Sort permanent breakpoints first. */
if (a_perm != b_perm)
return (a_perm < b_perm) - (a_perm > b_perm);
{
const int left_inserted = left->inserted;
const int left_duplicate = left->duplicate;
+ const int left_needs_update = left->needs_update;
const struct bp_target_info left_target_info = left->target_info;
/* Locations of tracepoints can never be duplicated. */
left->inserted = right->inserted;
left->duplicate = right->duplicate;
+ left->needs_update = right->needs_update;
left->target_info = right->target_info;
right->inserted = left_inserted;
right->duplicate = left_duplicate;
+ right->needs_update = left_needs_update;
right->target_info = left_target_info;
}
+/* Force the re-insertion of the locations at ADDRESS. This is called
+ once a new/deleted/modified duplicate location is found and we are evaluating
+ conditions on the target's side. Such conditions need to be updated on
+ the target. */
+
+static void
+force_breakpoint_reinsertion (struct bp_location *bl)
+{
+ struct bp_location **locp = NULL, **loc2p;
+ struct bp_location *loc;
+ CORE_ADDR address = 0;
+ int pspace_num;
+
+ address = bl->address;
+ pspace_num = bl->pspace->num;
+
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return;
+
+ /* Flag all breakpoint locations with this address and
+ the same program space as the location
+ as "its condition has changed". We need to
+ update the conditions on the target's side. */
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, address)
+ {
+ loc = *loc2p;
+
+ if (!is_breakpoint (loc->owner)
+ || pspace_num != loc->pspace->num)
+ continue;
+
+ /* Flag the location appropriately. We use a different state to
+ let everyone know that we already updated the set of locations
+ with addr bl->address and program space bl->pspace. This is so
+ we don't have to keep calling these functions just to mark locations
+ that have already been marked. */
+ loc->condition_changed = condition_updated;
+
+ /* Free the agent expression bytecode as well. We will compute
+ it later on. */
+ if (loc->cond_bytecode)
+ {
+ free_agent_expr (loc->cond_bytecode);
+ loc->cond_bytecode = NULL;
+ }
+ }
+}
+
/* If SHOULD_INSERT is false, do not insert any breakpoint locations
into the inferior, only remove already-inserted locations that no
longer should be inserted. Functions that delete a breakpoint or
struct breakpoint *b;
struct bp_location **locp, *loc;
struct cleanup *cleanups;
+ /* Last breakpoint location address that was marked for update. */
+ CORE_ADDR last_addr = 0;
+ /* Last breakpoint location program space that was marked for update. */
+ int last_pspace_num = -1;
/* Used in the duplicates detection below. When iterating over all
bp_locations, points to the first bp_location of a given address.
&& (*loc2p)->address == old_loc->address);
loc2p++)
{
- if (*loc2p == old_loc)
+ /* Check if this is a new/duplicated location or a duplicated
+ location that had its condition modified. If so, we want to send
+ its condition to the target if evaluation of conditions is taking
+ place there. */
+ if ((*loc2p)->condition_changed == condition_modified
+ && (last_addr != old_loc->address
+ || last_pspace_num != old_loc->pspace->num))
{
- found_object = 1;
- break;
+ force_breakpoint_reinsertion (*loc2p);
+ last_pspace_num = old_loc->pspace->num;
}
+
+ if (*loc2p == old_loc)
+ found_object = 1;
}
+ /* We have already handled this address, update it so that we don't
+ have to go through updates again. */
+ last_addr = old_loc->address;
+
+ /* Target-side condition evaluation: Handle deleted locations. */
+ if (!found_object)
+ force_breakpoint_reinsertion (old_loc);
+
/* If this location is no longer present, and inserted, look if
there's maybe a new location at the same address. If so,
mark that one inserted, and don't remove this one. This is
}
else
{
+ /* This location still exists, but it won't be kept in the
+ target since it may have been disabled. We proceed to
+ remove its target-side condition. */
+
/* The location is either no longer present, or got
disabled. See if there's another location at the
same address, in which case we don't need to remove
never duplicated. See the comments in field `duplicate' of
`struct bp_location'. */
|| is_tracepoint (b))
- continue;
+ {
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+ continue;
+ }
/* Permanent breakpoint should always be inserted. */
if (b->enable_state == bp_permanent && ! loc->inserted)
{
*loc_first_p = loc;
loc->duplicate = 0;
+
+ if (is_breakpoint (loc->owner) && loc->condition_changed)
+ {
+ loc->needs_update = 1;
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+ }
continue;
}
swap_insertion (loc, *loc_first_p);
loc->duplicate = 1;
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+
if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
&& b->enable_state != bp_permanent)
internal_error (__FILE__, __LINE__,
"a permanent breakpoint"));
}
- if (breakpoints_always_inserted_mode () && should_insert
+ if (breakpoints_always_inserted_mode ()
&& (have_live_inferiors ()
|| (gdbarch_has_global_breakpoints (target_gdbarch))))
- insert_breakpoint_locations ();
+ {
+ if (should_insert)
+ insert_breakpoint_locations ();
+ else
+ {
+ /* Though should_insert is false, we may need to update conditions
+ on the target's side if it is evaluating such conditions. We
+ only update conditions for locations that are marked
+ "needs_update". */
+ update_inserted_breakpoint_locations ();
+ }
+ }
if (should_insert)
download_tracepoint_locations ();
bp_location_dtor (struct bp_location *self)
{
xfree (self->cond);
+ if (self->cond_bytecode)
+ free_agent_expr (self->cond_bytecode);
xfree (self->function_name);
xfree (self->source_file);
}
int task, int ignore_count,
const struct breakpoint_ops *o,
int from_tty, int enabled,
- int internal)
+ int internal, unsigned flags)
{
internal_error_pure_virtual_called ();
}
int task, int ignore_count,
const struct breakpoint_ops *ops,
int from_tty, int enabled,
- int internal)
+ int internal, unsigned flags)
{
create_breakpoints_sal_default (gdbarch, canonical, lsal,
cond_string, type_wanted,
disposition, thread, task,
ignore_count, ops, from_tty,
- enabled, internal);
+ enabled, internal, flags);
}
static void
/* Nothing to mention. These breakpoints are internal. */
}
+/* Specific methods for probe breakpoints. */
+
+static int
+bkpt_probe_insert_location (struct bp_location *bl)
+{
+ int v = bkpt_insert_location (bl);
+
+ if (v == 0)
+ {
+ /* The insertion was successful, now let's set the probe's semaphore
+ if needed. */
+ bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch);
+ }
+
+ return v;
+}
+
+static int
+bkpt_probe_remove_location (struct bp_location *bl)
+{
+ /* Let's clear the semaphore before removing the location. */
+ bl->probe->pops->clear_semaphore (bl->probe, bl->gdbarch);
+
+ return bkpt_remove_location (bl);
+}
+
+static void
+bkpt_probe_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ struct linespec_sals lsal;
+
+ lsal.sals = parse_probes (arg, canonical);
+
+ *copy_arg = xstrdup (canonical->addr_string);
+ lsal.canonical = xstrdup (*copy_arg);
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+}
+
+static void
+bkpt_probe_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ *sals = parse_probes (s, NULL);
+ if (!sals->sals)
+ error (_("probe not found"));
+}
+
/* The breakpoint_ops structure to be used in tracepoints. */
static void
int task, int ignore_count,
const struct breakpoint_ops *ops,
int from_tty, int enabled,
- int internal)
+ int internal, unsigned flags)
{
create_breakpoints_sal_default (gdbarch, canonical, lsal,
cond_string, type_wanted,
disposition, thread, task,
ignore_count, ops, from_tty,
- enabled, internal);
+ enabled, internal, flags);
}
static void
struct breakpoint_ops tracepoint_breakpoint_ops;
+/* The breakpoint_ops structure to be use on tracepoints placed in a
+ static probe. */
+
+static void
+tracepoint_probe_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ /* We use the same method for breakpoint on probes. */
+ bkpt_probe_create_sals_from_address (arg, canonical, type_wanted,
+ addr_start, copy_arg);
+}
+
+static void
+tracepoint_probe_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ /* We use the same method for breakpoint on probes. */
+ bkpt_probe_decode_linespec (b, s, sals);
+}
+
+static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
+
/* The breakpoint_ops structure to be used on static tracepoints with
markers (`-m'). */
int task, int ignore_count,
const struct breakpoint_ops *ops,
int from_tty, int enabled,
- int internal)
+ int internal, unsigned flags)
{
int i;
addr_string, NULL,
cond_string, type_wanted, disposition,
thread, task, ignore_count, ops,
- from_tty, enabled, internal,
+ from_tty, enabled, internal, flags,
canonical->special_display);
/* Given that its possible to have multiple markers with
the same string id, if the user is creating a static
int task, int ignore_count,
const struct breakpoint_ops *ops,
int from_tty, int enabled,
- int internal)
+ int internal, unsigned flags)
{
create_breakpoints_sal (gdbarch, canonical, cond_string,
type_wanted, disposition,
thread, task, ignore_count, ops, from_tty,
- enabled, internal);
+ enabled, internal, flags);
}
/* Decode the line represented by S by calling decode_line_full. This is the
bpt->enable_state = bp_disabled;
+ /* Mark breakpoint locations modified. */
+ mark_breakpoint_modified (bpt);
+
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && is_tracepoint (bpt))
{
struct bp_location *loc = find_location_by_number (args);
if (loc)
{
- loc->enabled = 0;
+ if (loc->enabled)
+ {
+ loc->enabled = 0;
+ mark_breakpoint_location_modified (loc);
+ }
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && loc->owner
&& is_tracepoint (loc->owner))
if (bpt->enable_state != bp_permanent)
bpt->enable_state = bp_enabled;
+ bpt->enable_state = bp_enabled;
+
+ /* Mark breakpoint locations modified. */
+ mark_breakpoint_modified (bpt);
+
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && is_tracepoint (bpt))
{
struct bp_location *loc = find_location_by_number (args);
if (loc)
{
- loc->enabled = 1;
+ if (!loc->enabled)
+ {
+ loc->enabled = 1;
+ mark_breakpoint_location_modified (loc);
+ }
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && loc->owner
&& is_tracepoint (loc->owner))
int
catch_syscall_enabled (void)
{
- struct inferior *inf = current_inferior ();
+ struct catch_syscall_inferior_data *inf_data
+ = get_catch_syscall_inferior_data (current_inferior ());
- return inf->total_syscalls_count != 0;
+ return inf_data->total_syscalls_count != 0;
}
int
set_internalvar_integer (lookup_internalvar ("tpnum"), num);
}
-void
+static void
trace_command (char *arg, int from_tty)
{
+ struct breakpoint_ops *ops;
+ const char *arg_cp = arg;
+
+ if (arg && probe_linespec_to_ops (&arg_cp))
+ ops = &tracepoint_probe_breakpoint_ops;
+ else
+ ops = &tracepoint_breakpoint_ops;
+
if (create_breakpoint (get_current_arch (),
arg,
NULL, 0, 1 /* parse arg */,
bp_tracepoint /* type_wanted */,
0 /* Ignore count */,
pending_break_support,
- &tracepoint_breakpoint_ops,
+ ops,
from_tty,
1 /* enabled */,
- 0 /* internal */))
+ 0 /* internal */, 0))
set_tracepoint_count (breakpoint_count);
}
-void
+static void
ftrace_command (char *arg, int from_tty)
{
if (create_breakpoint (get_current_arch (),
&tracepoint_breakpoint_ops,
from_tty,
1 /* enabled */,
- 0 /* internal */))
+ 0 /* internal */, 0))
set_tracepoint_count (breakpoint_count);
}
/* strace command implementation. Creates a static tracepoint. */
-void
+static void
strace_command (char *arg, int from_tty)
{
struct breakpoint_ops *ops;
ops,
from_tty,
1 /* enabled */,
- 0 /* internal */))
+ 0 /* internal */, 0))
set_tracepoint_count (breakpoint_count);
}
&tracepoint_breakpoint_ops,
0 /* from_tty */,
utp->enabled /* enabled */,
- 0 /* internal */))
+ 0 /* internal */,
+ CREATE_BREAKPOINT_FLAGS_INSERTED))
return NULL;
set_tracepoint_count (breakpoint_count);
static void
clear_syscall_counts (struct inferior *inf)
{
- inf->total_syscalls_count = 0;
- inf->any_syscall_count = 0;
- VEC_free (int, inf->syscalls_counts);
+ struct catch_syscall_inferior_data *inf_data
+ = get_catch_syscall_inferior_data (inf);
+
+ inf_data->total_syscalls_count = 0;
+ inf_data->any_syscall_count = 0;
+ VEC_free (int, inf_data->syscalls_counts);
}
static void
ops->print_it = momentary_bkpt_print_it;
ops->print_mention = momentary_bkpt_print_mention;
+ /* Probe breakpoints. */
+ ops = &bkpt_probe_breakpoint_ops;
+ *ops = bkpt_breakpoint_ops;
+ ops->insert_location = bkpt_probe_insert_location;
+ ops->remove_location = bkpt_probe_remove_location;
+ ops->create_sals_from_address = bkpt_probe_create_sals_from_address;
+ ops->decode_linespec = bkpt_probe_decode_linespec;
+
/* GNU v3 exception catchpoints. */
ops = &gnu_v3_exception_catchpoint_ops;
*ops = bkpt_breakpoint_ops;
ops->create_breakpoints_sal = tracepoint_create_breakpoints_sal;
ops->decode_linespec = tracepoint_decode_linespec;
+ /* Probe tracepoints. */
+ ops = &tracepoint_probe_breakpoint_ops;
+ *ops = tracepoint_breakpoint_ops;
+ ops->create_sals_from_address = tracepoint_probe_create_sals_from_address;
+ ops->decode_linespec = tracepoint_probe_decode_linespec;
+
/* Static tracepoints with marker (`-m'). */
ops = &strace_marker_breakpoint_ops;
*ops = tracepoint_breakpoint_ops;
observer_attach_inferior_exit (clear_syscall_counts);
observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
- breakpoint_objfile_key = register_objfile_data ();
+ breakpoint_objfile_key
+ = register_objfile_data_with_cleanup (NULL, free_breakpoint_probes);
+
+ catch_syscall_inferior_data
+ = register_inferior_data_with_cleanup (catch_syscall_inferior_data_cleanup);
breakpoint_chain = 0;
/* Don't bother to call set_breakpoint_count. $bpnum isn't useful
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
+ add_setshow_enum_cmd ("condition-evaluation", class_breakpoint,
+ condition_evaluation_enums,
+ &condition_evaluation_mode_1, _("\
+Set mode of breakpoint condition evaluation."), _("\
+Show mode of breakpoint condition evaluation."), _("\
+When this is set to \"host\", breakpoint conditions will be\n\
+evaluated on the host's side by GDB. When it is set to \"target\",\n\
+breakpoint conditions will be downloaded to the target (if the target\n\
+supports such feature) and conditions will be evaluated on the target's side.\n\
+If this is set to \"auto\" (default), this will be automatically set to\n\
+\"target\" if it supports condition evaluation, otherwise it will\n\
+be set to \"gdb\""),
+ &set_condition_evaluation_mode,
+ &show_condition_evaluation_mode,
+ &breakpoint_set_cmdlist,
+ &breakpoint_show_cmdlist);
+
add_com ("break-range", class_breakpoint, break_range_command, _("\
Set a breakpoint for an address range.\n\
break-range START-LOCATION, END-LOCATION\n\