#include "value.h"
#include "command.h"
#include "inferior.h"
+#include "infrun.h"
#include "gdbthread.h"
#include "target.h"
#include "language.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 detach_single_step_breakpoints (void);
-static int single_step_breakpoint_inserted_here_p (struct address_space *,
- CORE_ADDR pc);
+static int find_single_step_breakpoint (struct address_space *aspace,
+ CORE_ADDR pc);
static void free_bp_location (struct bp_location *loc);
static void incref_bp_location (struct bp_location *loc);
/* Dynamic printf class type. */
struct breakpoint_ops dprintf_breakpoint_ops;
+/* One (or perhaps two) breakpoints used for software single
+ stepping. */
+
+static void *single_step_breakpoints[2];
+static struct gdbarch *single_step_gdbarch[2];
+
/* The style in which to perform a dynamic printf. This is a user
option because different output options have different tradeoffs;
if GDB does the printing, there is better error handling if there
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))
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 placed_address = target_info->placed_address;
+ int placed_size = target_info->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, &placed_address, &placed_size);
+
+ /* Update the final write buffer with this inserted
+ breakpoint's INSN. */
+ memcpy (writebuf + bp_addr - memaddr, bp + bptoffset, bp_size);
+ }
+}
+
/* Update BUF, which is LEN bytes read from the target address MEMADDR,
by replacing any memory breakpoints with their shadowed contents.
/* Left boundary, right boundary and median element of our binary
search. */
unsigned bc_l, bc_r, bc;
+ size_t i;
/* Find BC_L which is a leftmost element which may affect BUF
content. It is safe to report lower value but a failure to
if (!bp_location_has_shadow (bl))
continue;
- if (!breakpoint_address_match (bl->target_info.placed_address_space, 0,
- current_program_space->aspace, 0))
- continue;
-
- /* Addresses and length of the part of the breakpoint that
- we need to copy. */
- bp_addr = bl->target_info.placed_address;
- bp_size = bl->target_info.shadow_len;
-
- if (bp_addr + bp_size <= memaddr)
- /* The breakpoint is entirely before the chunk of memory we
- are reading. */
- continue;
- if (bp_addr >= memaddr + len)
- /* The breakpoint is entirely after the chunk of memory we are
- reading. */
- continue;
+ one_breakpoint_xfer_memory (readbuf, writebuf, writebuf_org,
+ memaddr, len, &bl->target_info, bl->gdbarch);
+ }
- /* Offset within shadow_contents. */
- if (bp_addr < memaddr)
- {
- /* Only copy the second part of the breakpoint. */
- bp_size -= memaddr - bp_addr;
- bptoffset = memaddr - bp_addr;
- bp_addr = memaddr;
- }
+ /* Now process single-step breakpoints. These are not found in the
+ bp_location array. */
+ for (i = 0; i < 2; i++)
+ {
+ struct bp_target_info *bp_tgt = single_step_breakpoints[i];
- if (bp_addr + bp_size > memaddr + len)
- {
- /* Only copy the first part of the breakpoint. */
- bp_size -= (bp_addr + bp_size) - (memaddr + len);
- }
+ if (bp_tgt != NULL)
+ {
+ struct gdbarch *gdbarch = single_step_gdbarch[i];
- if (readbuf != NULL)
- {
- /* Verify that the readbuf buffer does not overlap with
- the shadow_contents buffer. */
- gdb_assert (bl->target_info.shadow_contents >= readbuf + len
- || readbuf >= (bl->target_info.shadow_contents
- + bl->target_info.shadow_len));
-
- /* Update the read buffer with this inserted breakpoint's
- shadow. */
- memcpy (readbuf + bp_addr - memaddr,
- bl->target_info.shadow_contents + bptoffset, bp_size);
- }
- else
- {
- struct gdbarch *gdbarch = bl->gdbarch;
- const unsigned char *bp;
- CORE_ADDR placed_address = bl->target_info.placed_address;
- 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, bp_tgt, gdbarch);
+ }
+ }
}
+
\f
/* Return true if BPT is either a software breakpoint or a hardware
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))
+ 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
int *hw_breakpoint_error,
int *hw_bp_error_explained_already)
{
- int val = 0;
- const 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;
/* 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 = e.message;
+ bp_err = e.error;
+ bp_err_message = e.message;
}
}
else
/* 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)
+
+ /* 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 = 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
{
- 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);
+ 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);
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);
{
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);
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);
{
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,
|| !(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)
return 0;
}
-/* This function returns non-zero iff there is a software breakpoint
- inserted at PC. */
+/* Ignoring deprecated raw breakpoints, return non-zero iff there is a
+ software breakpoint inserted at PC. */
-int
-software_breakpoint_inserted_here_p (struct address_space *aspace,
- CORE_ADDR pc)
+static struct bp_location *
+find_non_raw_software_breakpoint_inserted_here (struct address_space *aspace,
+ CORE_ADDR pc)
{
struct bp_location *bl, **blp_tmp;
&& !section_is_mapped (bl->section))
continue; /* unmapped overlay -- can't be a match */
else
- return 1;
+ return bl;
}
}
+ return NULL;
+}
+
+/* This function returns non-zero iff there is a software breakpoint
+ inserted at PC. */
+
+int
+software_breakpoint_inserted_here_p (struct address_space *aspace,
+ CORE_ADDR pc)
+{
+ if (find_non_raw_software_breakpoint_inserted_here (aspace, pc) != NULL)
+ return 1;
+
/* Also check for software single-step breakpoints. */
if (single_step_breakpoint_inserted_here_p (aspace, pc))
return 1;
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;
}
- /* Evaluate Python breakpoints that have a "stop" method implemented. */
- if (b->py_bp_object)
- bs->stop = gdbpy_should_stop (b->py_bp_object);
+ /* Evaluate extension language breakpoints that have a "stop" method
+ implemented. */
+ bs->stop = breakpoint_ext_lang_cond_says_stop (b);
if (is_watchpoint (b))
{
&& 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)
{
/* 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. */
&& b->type == bp_std_terminate_master)
{
momentary_breakpoint_from_master (b, bp_std_terminate,
- &momentary_breakpoint_ops);
+ &momentary_breakpoint_ops, 1);
}
}
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);
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);
}
}
/* 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;
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;
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);
}
breakpoint_re_set_default (b);
}
+/* Copy SRC's shadow buffer and whatever else we'd set if we actually
+ inserted DEST, so we can remove it later, in case SRC is removed
+ first. */
+
+static void
+bp_target_info_copy_insertion_state (struct bp_target_info *dest,
+ const struct bp_target_info *src)
+{
+ dest->shadow_len = src->shadow_len;
+ memcpy (dest->shadow_contents, src->shadow_contents, src->shadow_len);
+ dest->placed_size = src->placed_size;
+}
+
static int
bkpt_insert_location (struct bp_location *bl)
{
return target_insert_hw_breakpoint (bl->gdbarch,
&bl->target_info);
else
- return target_insert_breakpoint (bl->gdbarch,
- &bl->target_info);
+ {
+ struct bp_target_info *bp_tgt = &bl->target_info;
+ int ret;
+ int sss_slot;
+
+ /* There is no need to insert a breakpoint if an unconditional
+ raw/sss breakpoint is already inserted at that location. */
+ sss_slot = find_single_step_breakpoint (bp_tgt->placed_address_space,
+ bp_tgt->placed_address);
+ if (sss_slot >= 0)
+ {
+ struct bp_target_info *sss_bp_tgt = single_step_breakpoints[sss_slot];
+
+ bp_target_info_copy_insertion_state (bp_tgt, sss_bp_tgt);
+ return 0;
+ }
+
+ return target_insert_breakpoint (bl->gdbarch, bp_tgt);
+ }
}
static int
if (bl->loc_type == bp_loc_hardware_breakpoint)
return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
else
- return target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+ {
+ struct bp_target_info *bp_tgt = &bl->target_info;
+ struct address_space *aspace = bp_tgt->placed_address_space;
+ CORE_ADDR address = bp_tgt->placed_address;
+
+ /* Only remove the breakpoint if there is no raw/sss breakpoint
+ still inserted at this location. Otherwise, we would be
+ effectively disabling the raw/sss breakpoint. */
+ if (single_step_breakpoint_inserted_here_p (aspace, address))
+ return 0;
+
+ return target_remove_breakpoint (bl->gdbarch, bp_tgt);
+ }
}
static int
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);
+ bl->probe.probe->pops->set_semaphore (bl->probe.probe,
+ bl->probe.objfile,
+ bl->gdbarch);
}
return v;
bkpt_probe_remove_location (struct bp_location *bl)
{
/* Let's clear the semaphore before removing the location. */
- bl->probe->pops->clear_semaphore (bl->probe, bl->gdbarch);
+ bl->probe.probe->pops->clear_semaphore (bl->probe.probe,
+ bl->probe.objfile,
+ bl->gdbarch);
return bkpt_remove_location (bl);
}
struct address_space *aspace, CORE_ADDR pc)
{
struct bp_target_info *bp_tgt;
+ struct bp_location *bl;
- bp_tgt = XZALLOC (struct bp_target_info);
+ bp_tgt = XCNEW (struct bp_target_info);
bp_tgt->placed_address_space = aspace;
bp_tgt->placed_address = pc;
+ /* If an unconditional non-raw breakpoint is already inserted at
+ that location, there's no need to insert another. However, with
+ target-side evaluation of breakpoint conditions, if the
+ breakpoint that is currently inserted on the target is
+ conditional, we need to make it unconditional. Note that a
+ breakpoint with target-side commands is not reported even if
+ unconditional, so we need to remove the commands from the target
+ as well. */
+ bl = find_non_raw_software_breakpoint_inserted_here (aspace, pc);
+ if (bl != NULL
+ && VEC_empty (agent_expr_p, bl->target_info.conditions)
+ && VEC_empty (agent_expr_p, bl->target_info.tcommands))
+ {
+ bp_target_info_copy_insertion_state (bp_tgt, &bl->target_info);
+ return bp_tgt;
+ }
+
if (target_insert_breakpoint (gdbarch, bp_tgt) != 0)
{
/* Could not insert the breakpoint. */
deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp)
{
struct bp_target_info *bp_tgt = bp;
+ struct address_space *aspace = bp_tgt->placed_address_space;
+ CORE_ADDR address = bp_tgt->placed_address;
+ struct bp_location *bl;
int ret;
- ret = target_remove_breakpoint (gdbarch, bp_tgt);
+ bl = find_non_raw_software_breakpoint_inserted_here (aspace, address);
+
+ /* Only remove the raw breakpoint if there are no other non-raw
+ breakpoints still inserted at this location. Otherwise, we would
+ be effectively disabling those breakpoints. */
+ if (bl == NULL)
+ ret = target_remove_breakpoint (gdbarch, bp_tgt);
+ else if (!VEC_empty (agent_expr_p, bl->target_info.conditions)
+ || !VEC_empty (agent_expr_p, bl->target_info.tcommands))
+ {
+ /* The target is evaluating conditions, and when we inserted the
+ software single-step breakpoint, we had made the breakpoint
+ unconditional and command-less on the target side. Reinsert
+ to restore the conditions/commands. */
+ ret = target_insert_breakpoint (bl->gdbarch, &bl->target_info);
+ }
+ else
+ ret = 0;
+
xfree (bp_tgt);
return ret;
}
-/* One (or perhaps two) breakpoints used for software single
- stepping. */
-
-static void *single_step_breakpoints[2];
-static struct gdbarch *single_step_gdbarch[2];
-
/* Create and insert a breakpoint for software single step. */
void
single_step_breakpoints[i]);
}
-/* Check whether a software single-step breakpoint is inserted at
- PC. */
+/* Find the software single-step breakpoint that inserted at PC.
+ Returns its slot if found, and -1 if not found. */
static int
-single_step_breakpoint_inserted_here_p (struct address_space *aspace,
- CORE_ADDR pc)
+find_single_step_breakpoint (struct address_space *aspace,
+ CORE_ADDR pc)
{
int i;
&& breakpoint_address_match (bp_tgt->placed_address_space,
bp_tgt->placed_address,
aspace, pc))
- return 1;
+ return i;
}
- return 0;
+ return -1;
+}
+
+/* Check whether a software single-step breakpoint is inserted at
+ PC. */
+
+int
+single_step_breakpoint_inserted_here_p (struct address_space *aspace,
+ CORE_ADDR pc)
+{
+ return find_single_step_breakpoint (aspace, pc) >= 0;
}
/* Returns 0 if 'bp' is NOT a syscall catchpoint,
}
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;
}
{
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. */