#define BP_TEMPFLAG 1
#define BP_HARDWAREFLAG 2
-/* Check watchpoint condition. */
+/* Evaluate watchpoint condition expression and check if its value changed.
+
+ P should be a pointer to struct bpstat, but is defined as a void *
+ in order for this function to be usable with catch_errors. */
static int
watchpoint_check (void *p)
struct value *new_val;
fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+
+ /* 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 not what we want. */
if ((b->val != NULL) != (new_val != NULL)
- || (b->val != NULL && !value_equal (b->val, new_val)))
+ || (b->val != NULL && !value_equal_contents (b->val, new_val)))
{
if (new_val != NULL)
{
{
struct breakpoint *b = bl->owner;
+ /* By definition, the inferior does not report stops at
+ tracepoints. */
+ if (b->type == bp_tracepoint)
+ return 0;
+
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
/* Pointer to the last thing in the chain currently. */
bpstat bs = root_bs;
int ix;
- int need_remove_insert, update_locations = 0;
+ int need_remove_insert;
- ALL_BP_LOCATIONS (bl, blp_tmp)
- {
- b = bl->owner;
- gdb_assert (b);
- if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
- continue;
+ /* ALL_BP_LOCATIONS iteration would break across
+ update_global_location_list possibly executed by
+ bpstat_check_breakpoint_conditions's inferior call. */
- /* For hardware watchpoints, we look only at the first location.
- The watchpoint_check function will work on entire expression,
- not the individual locations. For read watchopints, the
- watchpoints_triggered function have checked all locations
- already. */
- if (b->type == bp_hardware_watchpoint && bl != b->loc)
- continue;
+ ALL_BREAKPOINTS (b)
+ {
+ if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
+ continue;
- if (!bpstat_check_location (bl, aspace, bp_addr))
- continue;
+ for (bl = b->loc; bl != NULL; bl = bl->next)
+ {
+ /* For hardware watchpoints, we look only at the first location.
+ The watchpoint_check function will work on entire expression,
+ not the individual locations. For read watchopints, the
+ watchpoints_triggered function have checked all locations
+ already. */
+ if (b->type == bp_hardware_watchpoint && bl != b->loc)
+ break;
- /* Come here if it's a watchpoint, or if the break address matches */
+ if (bl->shlib_disabled)
+ continue;
- bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
+ if (!bpstat_check_location (bl, aspace, bp_addr))
+ continue;
- /* Assume we stop. Should we find watchpoint that is not actually
- triggered, or if condition of breakpoint is false, we'll reset
- 'stop' to 0. */
- bs->stop = 1;
- bs->print = 1;
+ /* Come here if it's a watchpoint, or if the break address matches */
- bpstat_check_watchpoint (bs);
- if (!bs->stop)
- continue;
+ bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
- if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master)
- /* We do not stop for these. */
- bs->stop = 0;
- else
- bpstat_check_breakpoint_conditions (bs, ptid);
-
- if (bs->stop)
- {
- if (b->enable_state != bp_disabled)
- ++(b->hit_count);
+ /* Assume we stop. Should we find watchpoint that is not actually
+ triggered, or if condition of breakpoint is false, we'll reset
+ 'stop' to 0. */
+ bs->stop = 1;
+ bs->print = 1;
- /* We will stop here */
- if (b->disposition == disp_disable)
- {
- if (b->enable_state != bp_permanent)
- b->enable_state = bp_disabled;
- update_locations = 1;
- }
- if (b->silent)
- bs->print = 0;
- bs->commands = b->commands;
- if (bs->commands
- && (strcmp ("silent", bs->commands->line) == 0
- || (xdb_commands && strcmp ("Q", bs->commands->line) == 0)))
- {
- bs->commands = bs->commands->next;
- bs->print = 0;
- }
- bs->commands = copy_command_lines (bs->commands);
- }
+ bpstat_check_watchpoint (bs);
+ if (!bs->stop)
+ continue;
- /* Print nothing for this entry if we dont stop or if we dont print. */
- if (bs->stop == 0 || bs->print == 0)
- bs->print_it = print_it_noop;
- }
+ if (b->type == bp_thread_event || b->type == bp_overlay_event
+ || b->type == bp_longjmp_master)
+ /* We do not stop for these. */
+ bs->stop = 0;
+ else
+ bpstat_check_breakpoint_conditions (bs, ptid);
+
+ if (bs->stop)
+ {
+ ++(b->hit_count);
- /* Delay this call which would break the ALL_BP_LOCATIONS iteration above. */
- if (update_locations)
- update_global_location_list (0);
+ /* We will stop here */
+ if (b->disposition == disp_disable)
+ {
+ if (b->enable_state != bp_permanent)
+ b->enable_state = bp_disabled;
+ update_global_location_list (0);
+ }
+ if (b->silent)
+ bs->print = 0;
+ bs->commands = b->commands;
+ if (bs->commands
+ && (strcmp ("silent", bs->commands->line) == 0
+ || (xdb_commands && strcmp ("Q",
+ bs->commands->line) == 0)))
+ {
+ bs->commands = bs->commands->next;
+ bs->print = 0;
+ }
+ bs->commands = copy_command_lines (bs->commands);
+ }
+
+ /* Print nothing for this entry if we dont stop or dont print. */
+ if (bs->stop == 0 || bs->print == 0)
+ bs->print_it = print_it_noop;
+ }
+ }
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
{
\f
+/* Print the LOC location out of the list of B->LOC locations. */
+
static void print_breakpoint_location (struct breakpoint *b,
struct bp_location *loc,
char *wrap_indent,
{
struct cleanup *old_chain = save_current_program_space ();
+ if (loc != NULL && loc->shlib_disabled)
+ loc = NULL;
+
if (loc != NULL)
set_current_program_space (loc->pspace);
- if (b->source_file)
+ if (b->source_file && loc)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
ui_out_field_int (uiout, "line", b->line_number);
}
- else if (!b->loc)
+ else if (loc)
{
- ui_out_field_string (uiout, "pending", b->addr_string);
- }
- else
- {
- print_address_symbolic (loc->address, stb->stream, demangle, "");
+ print_address_symbolic (loc->gdbarch, loc->address, stb->stream,
+ demangle, "");
ui_out_field_stream (uiout, "at", stb);
}
+ else
+ ui_out_field_string (uiout, "pending", b->addr_string);
do_cleanups (old_chain);
}
{
}
+/* Invalidate last known value of any hardware watchpoint if
+ the memory which that value represents has been written to by
+ GDB itself. */
+
+static void
+invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
+ const bfd_byte *data)
+{
+ struct breakpoint *bp;
+
+ ALL_BREAKPOINTS (bp)
+ if (bp->enable_state == bp_enabled
+ && bp->type == bp_hardware_watchpoint
+ && bp->val_valid && bp->val)
+ {
+ struct bp_location *loc;
+
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ if (loc->loc_type == bp_loc_hardware_watchpoint
+ && loc->address + loc->length > addr
+ && addr + len > loc->address)
+ {
+ value_free (bp->val);
+ bp->val = NULL;
+ bp->val_valid = 0;
+ }
+ }
+}
+
/* Use default_breakpoint_'s, or nothing if they aren't valid. */
struct symtabs_and_lines
observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
observer_attach_inferior_exit (clear_syscall_counts);
+ observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
breakpoint_chain = 0;
/* Don't bother to call set_breakpoint_count. $bpnum isn't useful