/* Everything about breakpoints, for GDB.
- Copyright (C) 1986-2013 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"
#undef savestring
#include "mi/mi-common.h"
-#include "python/python.h"
+#include "extension.h"
/* Enums for exception-handling support. */
enum exception_event_kind
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 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 void free_bp_location (struct bp_location *loc);
static void incref_bp_location (struct bp_location *loc);
static void decref_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);
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;
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;
}
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;
-
- /* 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 (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;
- int 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, &bl->target_info, bl->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
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)
{
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;
}
CORE_ADDR addr;
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);
+ 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 = TYPE_LENGTH (value_type (v));
+
+ 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;
+ }
+
+ /* Don't insert watchpoints if we're trying to step past the
+ instruction that triggered one. */
+ if ((bl->loc_type == bp_loc_hardware_watchpoint)
+ && stepping_past_nonsteppable_watchpoint ())
+ {
+ if (debug_infrun)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepping past non-steppable watchpoint. "
+ "skipping watchpoint at %s:%d\n",
+ paddress (bl->gdbarch, bl->address),
+ bl->length);
+ }
+ return 0;
+ }
+
return 1;
}
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
int modified = bl->needs_update;
struct bp_location *loc;
- /* For now, limit to agent-style dprintf breakpoints. */
- if (bl->owner->type != bp_dprintf
- || strcmp (dprintf_style, dprintf_style_agent) != 0)
- return;
+ /* 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
int *hw_breakpoint_error,
int *hw_bp_error_explained_already)
{
- int val = 0;
- char *hw_bp_err_string = NULL;
- struct gdb_exception e;
+ 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;
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;
+ }
}
}
/* No overlay handling: just set the breakpoint. */
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)
{
- val = 1;
- hw_bp_err_string = (char *) e.message;
+ 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",
/* Yes. This overlay section is mapped into memory. */
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)
{
- val = 1;
- hw_bp_err_string = (char *) e.message;
+ 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;
- *hw_bp_error_explained_already = hw_bp_err_string != NULL;
+ *hw_breakpoint_error = 1;
+ *hw_bp_error_explained_already = bp_err_message != NULL;
fprintf_unfiltered (tmp_error_stream,
"Cannot insert hardware breakpoint %d%s",
- bl->owner->number, hw_bp_err_string ? ":" : ".\n");
- if (hw_bp_err_string)
- fprintf_unfiltered (tmp_error_stream, "%s.\n", hw_bp_err_string);
+ 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. */
b->disposition = disp_del_at_next_stop;
printf_filtered (_("\
-Thread-specific breakpoint %d deleted - thread %d is gone.\n"),
+Thread-specific breakpoint %d deleted - thread %d no longer in the thread list.\n"),
b->number, tp->num);
/* Hide it from the user. */
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);
{
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);
}
{
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;
}
+ /* Just like single-step breakpoints. */
+ if (b->type == bp_single_step)
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
/* Longjmp and longjmp-resume breakpoints are also meaningless
after an exec. */
if (b->type == bp_longjmp || b->type == bp_longjmp_resume
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
val |= remove_breakpoint_1 (bl, mark_inserted);
}
- /* Detach single-step breakpoints as well. */
- detach_single_step_breakpoints ();
-
do_cleanups (old_chain);
return val;
}
|| !(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)
/* Also remove step-resume breakpoints. */
+ case bp_single_step:
+
+ /* Also remove single-step breakpoints. */
+
delete_breakpoint (b);
break;
return 0;
}
-/* Returns non-zero if there's a breakpoint inserted at PC, which is
- inserted using regular breakpoint_chain / bp_location array
- mechanism. This does not check for single-step breakpoints, which
- are inserted and removed using direct target manipulation. */
+/* Returns non-zero iff there's a breakpoint inserted at PC. */
int
-regular_breakpoint_inserted_here_p (struct address_space *aspace,
- CORE_ADDR pc)
+breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
struct bp_location *bl, **blp_tmp;
return 0;
}
-/* Returns non-zero iff there's either regular breakpoint
- or a single step breakpoint inserted at PC. */
-
-int
-breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
-{
- if (regular_breakpoint_inserted_here_p (aspace, pc))
- return 1;
-
- if (single_step_breakpoint_inserted_here_p (aspace, pc))
- return 1;
-
- return 0;
-}
-
/* This function returns non-zero iff there is a software breakpoint
inserted at PC. */
}
}
- /* Also check for software single-step breakpoints. */
- if (single_step_breakpoint_inserted_here_p (aspace, pc))
- return 1;
-
return 0;
}
/* See breakpoint.h. */
-enum bpstat_signal_value
+int
bpstat_explains_signal (bpstat bsp, enum gdb_signal sig)
{
- enum bpstat_signal_value result = BPSTAT_SIGNAL_NO;
-
for (; bsp != NULL; bsp = bsp->next)
{
- /* Ensure that, if we ever entered this loop, then we at least
- return BPSTAT_SIGNAL_HIDE. */
- enum bpstat_signal_value newval;
-
if (bsp->breakpoint_at == NULL)
{
/* A moribund location can never explain a signal other than
GDB_SIGNAL_TRAP. */
if (sig == GDB_SIGNAL_TRAP)
- newval = BPSTAT_SIGNAL_HIDE;
- else
- newval = BPSTAT_SIGNAL_NO;
+ return 1;
}
else
- newval = bsp->breakpoint_at->ops->explains_signal (bsp->breakpoint_at,
- sig);
-
- if (newval > result)
- result = newval;
+ {
+ if (bsp->breakpoint_at->ops->explains_signal (bsp->breakpoint_at,
+ sig))
+ return 1;
+ }
}
- return result;
+ return 0;
}
/* Put in *NUM the breakpoint number of the first breakpoint we are
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
mark = value_mark ();
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
the address of the array instead of its contents. This is
}
}
-
-/* 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;
- }
+ /* Evaluate extension language breakpoints that have a "stop" method
+ implemented. */
+ bs->stop = breakpoint_ext_lang_cond_says_stop (b);
+
+ if (is_watchpoint (b))
+ {
+ struct watchpoint *w = (struct watchpoint *) b;
+
+ cond = w->cond_exp;
+ }
+ else
+ cond = bl->cond;
+
+ if (cond && b->disposition != disp_del_at_next_stop)
+ {
+ int within_current_scope = 1;
+ struct watchpoint * w;
+
+ /* 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
- cond = bl->cond;
+ w = NULL;
- if (cond && b->disposition != disp_del_at_next_stop)
+ /* 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
{
- int within_current_scope = 1;
- struct watchpoint * w;
-
- /* 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
- {
- 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);
+ 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
- {
- 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 && value_is_zero)
- {
- bs->stop = 0;
+ 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--;
- 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);
+ }
}
}
}
+ /* Check if a moribund breakpoint explains the stop. */
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
{
if (breakpoint_location_address_match (loc, aspace, bp_addr))
}
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;
}
break;
case bp_breakpoint:
case bp_hardware_breakpoint:
+ case bp_single_step:
case bp_until:
case bp_finish:
case bp_shlib_event:
{bp_none, "?deleted?"},
{bp_breakpoint, "breakpoint"},
{bp_hardware_breakpoint, "hw breakpoint"},
+ {bp_single_step, "sw single-step"},
{bp_until, "until"},
{bp_finish, "finish"},
{bp_watchpoint, "watchpoint"},
case bp_breakpoint:
case bp_hardware_breakpoint:
+ case bp_single_step:
case bp_until:
case bp_finish:
case bp_longjmp:
&& 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)
{
have their addresses modified. */
return bpaddr;
}
+ else if (bptype == bp_single_step)
+ {
+ /* Single-step breakpoints should not have their addresses
+ modified. If there's any architectural constrain that
+ applies to this address, then it should have already been
+ taken into account when the breakpoint was created in the
+ first place. If we didn't do this, stepping through e.g.,
+ Thumb-2 IT blocks would break. */
+ return bpaddr;
+ }
else
{
CORE_ADDR adjusted_bpaddr;
switch (owner->type)
{
case bp_breakpoint:
+ case bp_single_step:
case bp_until:
case bp_finish:
case bp_longjmp:
/* 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;
}
}
}
-/* 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
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);
}
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;
observer_notify_breakpoint_created (b);
if (update_gll)
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
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
breakpoint_re_set ();
}
+/* Create a new single-step breakpoint for thread THREAD, with no
+ locations. */
+
+static struct breakpoint *
+new_single_step_breakpoint (int thread, struct gdbarch *gdbarch)
+{
+ struct breakpoint *b = XNEW (struct breakpoint);
+
+ init_raw_breakpoint_without_location (b, gdbarch, bp_single_step,
+ &momentary_breakpoint_ops);
+
+ b->disposition = disp_donttouch;
+ b->frame_id = null_frame_id;
+
+ b->thread = thread;
+ gdb_assert (b->thread != 0);
+
+ add_to_breakpoint_chain (b);
+
+ return b;
+}
-/* Set a breakpoint that will evaporate an end of command
- at address specified by SAL.
- Restrict it to frame FRAME if FRAME is nonzero. */
+/* Set a momentary breakpoint of type TYPE at address specified by
+ SAL. If FRAME_ID is valid, the breakpoint is restricted to that
+ frame. */
struct breakpoint *
set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal,
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->probe = orig->loc->probe;
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 *
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;
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 (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);
msym = lookup_minimal_symbol_by_pc (sal->pc);
if (msym.minsym)
- sal->section = SYMBOL_OBJ_SECTION (msym.objfile, msym.minsym);
+ sal->section = MSYMBOL_OBJ_SECTION (msym.objfile, msym.minsym);
do_cleanups (old_chain);
}
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:
/* Implement the "explains_signal" breakpoint_ops method for
watchpoints. */
-static enum bpstat_signal_value
+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 BPSTAT_SIGNAL_NO;
+ return 0;
- return BPSTAT_SIGNAL_HIDE;
+ return 1;
}
/* The breakpoint_ops structure to be used in hardware watchpoints. */
struct expression *exp;
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;
const char *exp_start = NULL;
const char *exp_end = NULL;
mark = value_mark ();
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)
{
int ret;
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;
}
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. */
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;
}
}
}
+/* 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;
"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. */
if (self->cond_bytecode)
free_agent_expr (self->cond_bytecode);
xfree (self->function_name);
+
+ 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 =
/* The default 'explains_signal' method. */
-static enum bpstat_signal_value
+static int
base_breakpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig)
{
- return BPSTAT_SIGNAL_HIDE;
+ return 1;
}
/* The default "after_condition_true" method. */
bkpt_insert_location (struct bp_location *bl)
{
if (bl->loc_type == bp_loc_hardware_breakpoint)
- return target_insert_hw_breakpoint (bl->gdbarch,
- &bl->target_info);
+ return target_insert_hw_breakpoint (bl->gdbarch, &bl->target_info);
else
- return target_insert_breakpoint (bl->gdbarch,
- &bl->target_info);
+ return target_insert_breakpoint (bl->gdbarch, &bl->target_info);
}
static int
return 1;
}
+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)
{
{
/* The insertion was successful, now let's set the probe's semaphore
if needed. */
- bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch);
+ if (bl->probe.probe->pops->set_semaphore != NULL)
+ 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);
+ if (bl->probe.probe->pops->clear_semaphore != NULL)
+ bl->probe.probe->pops->clear_semaphore (bl->probe.probe,
+ bl->probe.objfile,
+ bl->gdbarch);
return bkpt_remove_location (bl);
}
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
/* 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);
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.
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);
}
&& is_tracepoint (loc->owner))
target_disable_tracepoint (loc);
}
- update_global_location_list (0);
+ update_global_location_list (UGLL_DONT_INSERT);
}
else
map_breakpoint_numbers (num, do_map_disable_breakpoint, NULL);
bpt->disposition = disposition;
bpt->enable_count = count;
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
observer_notify_breakpoint_modified (bpt);
}
&& is_tracepoint (loc->owner))
target_enable_tracepoint (loc);
}
- update_global_location_list (1);
+ update_global_location_list (UGLL_MAY_INSERT);
}
else
map_breakpoint_numbers (num, do_map_enable_breakpoint, NULL);
}
}
-/* Create and insert a raw software breakpoint at PC. Return an
- identifier, which should be used to remove the breakpoint later.
- In general, places which call this should be using something on the
- breakpoint chain instead; this function should be eliminated
- someday. */
-
-void *
-deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch,
- struct address_space *aspace, CORE_ADDR pc)
-{
- struct bp_target_info *bp_tgt;
-
- bp_tgt = XZALLOC (struct bp_target_info);
-
- bp_tgt->placed_address_space = aspace;
- bp_tgt->placed_address = pc;
-
- if (target_insert_breakpoint (gdbarch, bp_tgt) != 0)
- {
- /* Could not insert the breakpoint. */
- xfree (bp_tgt);
- return NULL;
- }
-
- return bp_tgt;
-}
-
-/* Remove a breakpoint BP inserted by
- deprecated_insert_raw_breakpoint. */
-
-int
-deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp)
-{
- struct bp_target_info *bp_tgt = bp;
- int ret;
-
- ret = target_remove_breakpoint (gdbarch, bp_tgt);
- 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
struct address_space *aspace,
CORE_ADDR next_pc)
{
- void **bpt_p;
+ struct thread_info *tp = inferior_thread ();
+ struct symtab_and_line sal;
+ CORE_ADDR pc = next_pc;
- if (single_step_breakpoints[0] == NULL)
- {
- bpt_p = &single_step_breakpoints[0];
- single_step_gdbarch[0] = gdbarch;
- }
- else
+ if (tp->control.single_step_breakpoints == NULL)
{
- gdb_assert (single_step_breakpoints[1] == NULL);
- bpt_p = &single_step_breakpoints[1];
- single_step_gdbarch[1] = gdbarch;
+ tp->control.single_step_breakpoints
+ = new_single_step_breakpoint (tp->num, gdbarch);
}
- /* NOTE drow/2006-04-11: A future improvement to this function would
- be to only create the breakpoints once, and actually put them on
- the breakpoint chain. That would let us use set_raw_breakpoint.
- We could adjust the addresses each time they were needed. Doing
- this requires corresponding changes elsewhere where single step
- breakpoints are handled, however. So, for now, we use this. */
+ sal = find_pc_line (pc, 0);
+ sal.pc = pc;
+ sal.section = find_pc_overlay (pc);
+ sal.explicit_pc = 1;
+ add_location_to_breakpoint (tp->control.single_step_breakpoints, &sal);
- *bpt_p = deprecated_insert_raw_breakpoint (gdbarch, aspace, next_pc);
- if (*bpt_p == NULL)
- error (_("Could not insert single-step breakpoint at %s"),
- paddress (gdbarch, next_pc));
+ update_global_location_list (UGLL_INSERT);
}
-/* Check if the breakpoints used for software single stepping
- were inserted or not. */
+/* See breakpoint.h. */
int
-single_step_breakpoints_inserted (void)
+breakpoint_has_location_inserted_here (struct breakpoint *bp,
+ struct address_space *aspace,
+ CORE_ADDR pc)
{
- return (single_step_breakpoints[0] != NULL
- || single_step_breakpoints[1] != NULL);
-}
-
-/* Remove and delete any breakpoints used for software single step. */
-
-void
-remove_single_step_breakpoints (void)
-{
- gdb_assert (single_step_breakpoints[0] != NULL);
-
- /* See insert_single_step_breakpoint for more about this deprecated
- call. */
- deprecated_remove_raw_breakpoint (single_step_gdbarch[0],
- single_step_breakpoints[0]);
- single_step_gdbarch[0] = NULL;
- single_step_breakpoints[0] = NULL;
-
- if (single_step_breakpoints[1] != NULL)
- {
- deprecated_remove_raw_breakpoint (single_step_gdbarch[1],
- single_step_breakpoints[1]);
- single_step_gdbarch[1] = NULL;
- single_step_breakpoints[1] = NULL;
- }
-}
-
-/* Delete software single step breakpoints without removing them from
- the inferior. This is intended to be used if the inferior's address
- space where they were inserted is already gone, e.g. after exit or
- exec. */
-
-void
-cancel_single_step_breakpoints (void)
-{
- int i;
-
- for (i = 0; i < 2; i++)
- if (single_step_breakpoints[i])
- {
- xfree (single_step_breakpoints[i]);
- single_step_breakpoints[i] = NULL;
- single_step_gdbarch[i] = NULL;
- }
-}
-
-/* Detach software single-step breakpoints from INFERIOR_PTID without
- removing them. */
+ struct bp_location *loc;
-static void
-detach_single_step_breakpoints (void)
-{
- int i;
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ if (loc->inserted
+ && breakpoint_location_address_match (loc, aspace, pc))
+ return 1;
- for (i = 0; i < 2; i++)
- if (single_step_breakpoints[i])
- target_remove_breakpoint (single_step_gdbarch[i],
- single_step_breakpoints[i]);
+ return 0;
}
/* Check whether a software single-step breakpoint is inserted at
PC. */
-static int
-single_step_breakpoint_inserted_here_p (struct address_space *aspace,
+int
+single_step_breakpoint_inserted_here_p (struct address_space *aspace,
CORE_ADDR pc)
{
- int i;
+ struct breakpoint *bpt;
- for (i = 0; i < 2; i++)
+ ALL_BREAKPOINTS (bpt)
{
- 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,
- aspace, pc))
+ if (bpt->type == bp_single_step
+ && breakpoint_has_location_inserted_here (bpt, aspace, pc))
return 1;
}
-
return 0;
}
}
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)
{
struct breakpoint *t;
int tpnum;
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;
}
}
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
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 *
ops->print_mention = bkpt_print_mention;
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. */
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);
&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,