static void catch_command (char *, int);
-static int can_use_hardware_watchpoint (struct value *);
+static int can_use_hardware_watchpoint (struct value *, int);
static void break_command_1 (char *, int, int);
/* Are overlay event breakpoints enabled? */
static int overlay_events_enabled;
+/* See description in breakpoint.h. */
+int target_exact_watchpoints = 0;
+
/* Walk the following statement or block through all breakpoints.
ALL_BREAKPOINTS_SAFE does so even if the statment deletes the
current breakpoint. */
observer_notify_breakpoint_modified (b->number);
}
+/* Set the internal `silent' flag on the breakpoint. Note that this
+ is not the same as the "silent" that may appear in the breakpoint's
+ commands. */
+
+void
+breakpoint_set_silent (struct breakpoint *b, int silent)
+{
+ int old_silent = b->silent;
+
+ b->silent = silent;
+ if (old_silent != silent)
+ observer_notify_breakpoint_modified (b->number);
+}
+
+/* Set the thread for this breakpoint. If THREAD is -1, make the
+ breakpoint work for any thread. */
+
+void
+breakpoint_set_thread (struct breakpoint *b, int thread)
+{
+ int old_thread = b->thread;
+
+ b->thread = thread;
+ if (old_thread != thread)
+ observer_notify_breakpoint_modified (b->number);
+}
+
+/* Set the task for this breakpoint. If TASK is 0, make the
+ breakpoint work for any task. */
+
+void
+breakpoint_set_task (struct breakpoint *b, int task)
+{
+ int old_task = b->task;
+
+ b->task = task;
+ if (old_task != task)
+ observer_notify_breakpoint_modified (b->number);
+}
+
void
check_tracepoint_command (char *line, void *closure)
{
b->val_valid = 1;
}
- /* Change the type of breakpoint between hardware assisted or
- an ordinary watchpoint depending on the hardware support
- and free hardware slots. REPARSE is set when the inferior
- is started. */
- if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
- && reparse)
- {
- int i, mem_cnt, other_type_used;
-
- /* We need to determine how many resources are already
- used for all other hardware watchpoints to see if we
- still have enough resources to also fit this watchpoint
- in as well. To avoid the hw_watchpoint_used_count call
- below from counting this watchpoint, make sure that it
- is marked as a software watchpoint. */
- b->type = bp_watchpoint;
- i = hw_watchpoint_used_count (bp_hardware_watchpoint,
- &other_type_used);
- mem_cnt = can_use_hardware_watchpoint (val_chain);
-
- if (!mem_cnt)
- b->type = bp_watchpoint;
- else
- {
- int target_resources_ok = target_can_use_hardware_watchpoint
- (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
- if (target_resources_ok <= 0)
- b->type = bp_watchpoint;
- else
- b->type = bp_hardware_watchpoint;
- }
- }
-
frame_pspace = get_frame_program_space (get_selected_frame (NULL));
/* Look at each value on the value chain. */
- for (v = val_chain; v; v = next)
+ for (v = val_chain; v; v = value_next (v))
{
/* If it's a memory location, and GDB actually needed
its contents to evaluate the expression, then we
loc->watchpoint_type = type;
}
}
+ }
+
+ /* Change the type of breakpoint between hardware assisted or
+ an ordinary watchpoint depending on the hardware support
+ and free hardware slots. REPARSE is set when the inferior
+ is started. */
+ if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
+ && reparse)
+ {
+ int reg_cnt;
+ enum bp_loc_type loc_type;
+ struct bp_location *bl;
+
+ reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact);
+
+ if (reg_cnt)
+ {
+ int i, target_resources_ok, other_type_used;
+ enum enable_state orig_enable_state;
+
+ /* We need to determine how many resources are already
+ used for all other hardware watchpoints plus this one
+ to see if we still have enough resources to also fit
+ this watchpoint in as well. To guarantee the
+ hw_watchpoint_used_count call below counts this
+ watchpoint, make sure that it is marked as a hardware
+ watchpoint. */
+ b->type = bp_hardware_watchpoint;
+
+ /* hw_watchpoint_used_count ignores disabled watchpoints,
+ and b might be disabled if we're being called from
+ do_enable_breakpoint. */
+ orig_enable_state = b->enable_state;
+ b->enable_state = bp_enabled;
+
+ i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+ &other_type_used);
+
+ b->enable_state = orig_enable_state;
+
+ target_resources_ok = target_can_use_hardware_watchpoint
+ (bp_hardware_watchpoint, i, other_type_used);
+ if (target_resources_ok <= 0)
+ b->type = bp_watchpoint;
+ }
+ else
+ b->type = bp_watchpoint;
+ loc_type = (b->type == bp_watchpoint? bp_loc_other
+ : bp_loc_hardware_watchpoint);
+ for (bl = b->loc; bl; bl = bl->next)
+ bl->loc_type = loc_type;
+ }
+
+ for (v = val_chain; v; v = next)
+ {
next = value_next (v);
if (v != b->val)
value_free (v);
|| is_watchpoint (b));
}
+/* Return true if this breakpoint was set by the user, false if it is
+ internal or momentary. */
+
+int
+user_breakpoint_p (struct breakpoint *b)
+{
+ return user_settable_breakpoint (b) && b->number > 0;
+}
+
/* Print information on user settable breakpoint (watchpoint, etc)
number BNUM. If BNUM is -1 print all user-settable breakpoints.
If ALLFLAG is non-zero, include non-user-settable breakpoints. If
if (filter && !filter (b))
continue;
- if (allflag || (user_settable_breakpoint (b)
- && b->number > 0))
+ if (allflag || user_breakpoint_p (b))
{
int addr_bit, type_len;
/* We only print out user settable breakpoints unless the
allflag is set. */
- if (allflag || (user_settable_breakpoint (b)
- && b->number > 0))
+ if (allflag || user_breakpoint_p (b))
print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
}
}
return b;
}
+/* Remove JIT code registration and unregistration breakpoint(s). */
+
+void
+remove_jit_event_breakpoints (void)
+{
+ struct breakpoint *b, *b_tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, b_tmp)
+ if (b->type == bp_jit_event
+ && b->loc->pspace == current_program_space)
+ delete_breakpoint (b);
+}
+
void
remove_solib_event_breakpoints (void)
{
insert_catch_fork,
remove_catch_fork,
breakpoint_hit_catch_fork,
+ NULL, /* resources_needed */
print_it_catch_fork,
print_one_catch_fork,
print_mention_catch_fork,
insert_catch_vfork,
remove_catch_vfork,
breakpoint_hit_catch_vfork,
+ NULL, /* resources_needed */
print_it_catch_vfork,
print_one_catch_vfork,
print_mention_catch_vfork,
insert_catch_syscall,
remove_catch_syscall,
breakpoint_hit_catch_syscall,
+ NULL, /* resources_needed */
print_it_catch_syscall,
print_one_catch_syscall,
print_mention_catch_syscall,
insert_catch_exec,
remove_catch_exec,
breakpoint_hit_catch_exec,
+ NULL, /* resources_needed */
print_it_catch_exec,
print_one_catch_exec,
print_mention_catch_exec,
static int
hw_watchpoint_used_count (enum bptype type, int *other_type_used)
{
- struct breakpoint *b;
int i = 0;
+ struct breakpoint *b;
+ struct bp_location *bl;
*other_type_used = 0;
ALL_BREAKPOINTS (b)
- {
- if (breakpoint_enabled (b))
- {
+ {
+ if (!breakpoint_enabled (b))
+ continue;
+
if (b->type == type)
- i++;
+ for (bl = b->loc; bl; bl = bl->next)
+ {
+ /* Special types of hardware watchpoints may use more than
+ one register. */
+ if (b->ops && b->ops->resources_needed)
+ i += b->ops->resources_needed (bl);
+ else
+ i++;
+ }
else if (is_hardware_watchpoint (b))
*other_type_used = 1;
- }
- }
+ }
+
return i;
}
static int
insert_watchpoint (struct bp_location *bl)
{
- return target_insert_watchpoint (bl->address, bl->length,
- bl->watchpoint_type, bl->owner->cond_exp);
+ int length = bl->owner->exact? 1 : bl->length;
+
+ return target_insert_watchpoint (bl->address, length, bl->watchpoint_type,
+ bl->owner->cond_exp);
}
/* Implement the "remove" breakpoint_ops method for hardware watchpoints. */
static int
remove_watchpoint (struct bp_location *bl)
{
- return target_remove_watchpoint (bl->address, bl->length,
- bl->watchpoint_type, bl->owner->cond_exp);
+ int length = bl->owner->exact? 1 : bl->length;
+
+ return target_remove_watchpoint (bl->address, length, bl->watchpoint_type,
+ bl->owner->cond_exp);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+ hardware watchpoints. */
+
+static int
+resources_needed_watchpoint (const struct bp_location *bl)
+{
+ int length = bl->owner->exact? 1 : bl->length;
+
+ return target_region_ok_for_hw_watchpoint (bl->address, length);
}
/* The breakpoint_ops structure to be used in hardware watchpoints. */
insert_watchpoint,
remove_watchpoint,
NULL, /* breakpoint_hit */
+ resources_needed_watchpoint,
NULL, /* print_it */
NULL, /* print_one */
NULL, /* print_mention */
char *cond_end = NULL;
int i, other_type_used, target_resources_ok = 0;
enum bptype bp_type;
- int mem_cnt = 0;
+ int reg_cnt = 0;
int thread = -1;
int pc = 0;
else
bp_type = bp_hardware_watchpoint;
- mem_cnt = can_use_hardware_watchpoint (val);
- if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint)
+ reg_cnt = can_use_hardware_watchpoint (val, target_exact_watchpoints);
+ if (reg_cnt == 0 && bp_type != bp_hardware_watchpoint)
error (_("Expression cannot be implemented with read/access watchpoint."));
- if (mem_cnt != 0)
+ if (reg_cnt != 0)
{
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
- target_can_use_hardware_watchpoint (bp_type, i + mem_cnt,
+ target_can_use_hardware_watchpoint (bp_type, i + reg_cnt,
other_type_used);
if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
error (_("Target does not support this type of hardware watchpoint."));
/* Change the type of breakpoint to an ordinary watchpoint if a
hardware watchpoint could not be set. */
- if (!mem_cnt || target_resources_ok <= 0)
+ if (!reg_cnt || target_resources_ok <= 0)
bp_type = bp_watchpoint;
frame = block_innermost_frame (exp_valid_block);
b->val_valid = 1;
b->ops = &watchpoint_breakpoint_ops;
+ /* Use an exact watchpoint when there's only one memory region to be
+ watched, and only one debug register is needed to watch it. */
+ b->exact = target_exact_watchpoints && reg_cnt == 1;
+
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
update_global_location_list (1);
}
-/* Return count of locations need to be watched and can be handled in
- hardware. If the watchpoint can not be handled in hardware return
- zero. */
+/* Return count of debug registers needed to watch the given expression.
+ If EXACT_WATCHPOINTS is 1, then consider that only the address of
+ the start of the watched region will be monitored (i.e., all accesses
+ will be aligned). This uses less debug registers on some targets.
+
+ If the watchpoint cannot be handled in hardware return zero. */
static int
-can_use_hardware_watchpoint (struct value *v)
+can_use_hardware_watchpoint (struct value *v, int exact_watchpoints)
{
int found_memory_cnt = 0;
struct value *head = v;
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR vaddr = value_address (v);
- int len = TYPE_LENGTH (value_type (v));
+ int len;
+ int num_regs;
- if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+ len = (exact_watchpoints
+ && is_scalar_type_recursive (vtype))?
+ 1 : TYPE_LENGTH (value_type (v));
+
+ num_regs = target_region_ok_for_hw_watchpoint (vaddr, len);
+ if (!num_regs)
return 0;
else
- found_memory_cnt++;
+ found_memory_cnt += num_regs;
}
}
}
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* resources_needed */
print_exception_catchpoint,
print_one_exception_catchpoint,
print_mention_exception_catchpoint,
error (_("No breakpoint number %d."), bptnum);
}
-void
-make_breakpoint_silent (struct breakpoint *b)
-{
- /* Silence the breakpoint. */
- b->silent = 1;
-}
-
/* Command to set ignore-count of breakpoint N to COUNT. */
static void
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp) || tp->number < 0)
+ if (!user_breakpoint_p (tp))
continue;
/* If we have a filter, only save the breakpoints it accepts. */
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp) || tp->number < 0)
+ if (!user_breakpoint_p (tp))
continue;
/* If we have a filter, only save the breakpoints it accepts. */