#include "value.h"
#include "command.h"
#include "inferior.h"
+#include "infrun.h"
#include "gdbthread.h"
#include "target.h"
#include "language.h"
-#include <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"
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;
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
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;
}
}
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;
}
/* Release commands left over from a previous insert. */
VEC_free (agent_expr_p, bl->target_info.tcommands);
- /* For now, limit to agent-style dprintf breakpoints. */
- if (bl->owner->type != bp_dprintf
- || strcmp (dprintf_style, dprintf_style_agent) != 0)
+ if (!target_can_run_breakpoint_commands ())
return;
- if (!target_can_run_breakpoint_commands ())
+ /* 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
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;
+ }
}
}
bl->section);
/* Set a software (trap) breakpoint at the LMA. */
bl->overlay_target_info = bl->target_info;
- bl->overlay_target_info.placed_address = addr;
+ bl->overlay_target_info.reqstd_address = addr;
/* No overlay handling: just set the breakpoint. */
TRY_CATCH (e, RETURN_MASK_ALL)
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 (necessary if this is a
- HW breakpoint, but SW breakpoints likewise) 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. */
+ 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)
- && solib_name_from_address (bl->pspace, bl->address))
+ && 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. */
bl->shlib_disabled = 1;
/* 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. */
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 *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");
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;
}
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
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;
return;
}
- /* If this is a thread-specific breakpoint, don't waste cpu evaluating the
- condition if this isn't the specified thread. */
- if (b->thread != -1 && b->thread != thread_id)
+ /* 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)))
+
{
bs->stop = 0;
return;
}
}
+ /* 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;
}
if (objfile == NULL)
return;
- /* If the file is a shared library not loaded by the user then
- solib_unloaded was notified and disable_breakpoints_in_unloaded_shlib
- was called. In that case there is no need to take action again. */
- if ((objfile->flags & OBJF_SHARED) && !(objfile->flags & OBJF_USERLOADED))
+ /* 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)
if (is_addr_in_objfile (loc_addr, objfile))
{
loc->shlib_disabled = 1;
- loc->inserted = 0;
+ /* 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);
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);
-/* Set a breakpoint that will evaporate an end of command
- at address specified by SAL.
- Restrict it to frame FRAME if FRAME is nonzero. */
+ add_to_breakpoint_chain (b);
+
+ return b;
+}
+
+/* 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:
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;
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. */
}
}
}
+/* 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. */
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 = XCNEW (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)
+ if (tp->control.single_step_breakpoints == NULL)
{
- bpt_p = &single_step_breakpoints[0];
- single_step_gdbarch[0] = gdbarch;
- }
- else
- {
- 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. */
&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,