aboutsummaryrefslogtreecommitdiff
path: root/gdb/breakpoint.c
diff options
context:
space:
mode:
authorThiago Jung Bauermann <bauerman@br.ibm.com>2011-01-11 19:23:03 +0000
committerThiago Jung Bauermann <bauerman@br.ibm.com>2011-01-11 19:23:03 +0000
commite09342b536073e978e30460267e144063843cd17 (patch)
tree4b5abae529e18768c8f16fcb74a528a8353e73f4 /gdb/breakpoint.c
parent9fa40276f0a747e238e608672231ec28fa614619 (diff)
downloadfsf-binutils-gdb-e09342b536073e978e30460267e144063843cd17.zip
fsf-binutils-gdb-e09342b536073e978e30460267e144063843cd17.tar.gz
fsf-binutils-gdb-e09342b536073e978e30460267e144063843cd17.tar.bz2
2011-01-11 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Thiago Jung Bauermann <bauerman@br.ibm.com> Implement support for PowerPC BookE ranged watchpoints. gdb/ * breakpoint.h (struct breakpoint_ops) <resources_needed>: New method. Initialize to NULL in all existing breakpoint_ops instances. (struct breakpoint) <exact>: New field. (target_exact_watchpoints): Declare external global. * breakpoint.c (target_exact_watchpoints): New global flag. (update_watchpoint): Set b->type to bp_hardware_watchpoint and b->enable_state to bp_enabled before calling hw_watchpoint_used_count. (hw_watchpoint_used_count): Iterate over all bp_locations in a watchpoint. Call breakpoint's breakpoint_ops.resources_needed if available. (insert_watchpoint, remove_watchpoint): Use fixed length of 1 byte if the watchpoint is exact. (resources_needed_watchpoint): New function. (watchpoint_breakpoint_ops): Add resources_needed_watchpoint. (watch_command_1): Set b->exact if the user asked for an exact watchpoint and one can be set. (can_use_hardware_watchpoint): Add exact_watchpoints argument. Pass fixed length of 1 to target_region_ok_for_hw_watchpoint if the user asks for an exact watchpoint and one can be set. Return number of needed debug registers to watch the expression. * gdbtypes.c (is_scalar_type): New function, based on valprint.c:scalar_type_p. (is_scalar_type_recursive): New function. * gdbtypes.h (is_scalar_type_recursive): Declare. * ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when ranged watchpoints are available. (create_watchpoint_request): New function. (ppc_linux_insert_watchpoint, ppc_linux_remove_watchpoint): Use create_watchpoint_request. * rs6000-tdep.c (show_powerpc_exact_watchpoints): New function. (_initialize_rs6000_tdep): Add `exact-watchpoints' boolean to the `set powerpc' and `show powerpc' commands. * target.h (struct target_ops) <to_region_ok_for_hw_watchpoint>: Mention documentation comment in the target macro. (target_region_ok_for_hw_watchpoint): Document return value. gdb/doc/ * gdb.texinfo (PowerPC Embedded): Document ranged watchpoints and the "set powerpc exact-watchpoints" flag.
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r--gdb/breakpoint.c135
1 files changed, 97 insertions, 38 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8c1a4e0..3db9401 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -98,7 +98,7 @@ static void clear_command (char *, int);
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);
@@ -351,6 +351,9 @@ static int executing_breakpoint_commands;
/* 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. */
@@ -1481,29 +1484,41 @@ update_watchpoint (struct breakpoint *b, int reparse)
if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
&& reparse)
{
- int mem_cnt;
+ int reg_cnt;
enum bp_loc_type loc_type;
struct bp_location *bl;
- mem_cnt = can_use_hardware_watchpoint (val_chain);
- if (mem_cnt)
+ 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 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;
+ 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);
- 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_hardware_watchpoint;
+ 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;
@@ -6094,6 +6109,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
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,
@@ -6189,6 +6205,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
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,
@@ -6472,6 +6489,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
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,
@@ -6625,6 +6643,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
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,
@@ -6665,20 +6684,30 @@ hw_breakpoint_used_count (void)
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;
}
@@ -8226,8 +8255,10 @@ watchpoint_exp_is_const (const struct expression *exp)
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. */
@@ -8235,8 +8266,21 @@ insert_watchpoint (struct bp_location *bl)
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. */
@@ -8246,6 +8290,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
insert_watchpoint,
remove_watchpoint,
NULL, /* breakpoint_hit */
+ resources_needed_watchpoint,
NULL, /* print_it */
NULL, /* print_one */
NULL, /* print_mention */
@@ -8272,7 +8317,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
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;
@@ -8407,14 +8452,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
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."));
@@ -8426,7 +8471,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
/* 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);
@@ -8497,6 +8542,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
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
@@ -8536,12 +8585,15 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
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;
@@ -8594,12 +8646,18 @@ can_use_hardware_watchpoint (struct value *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;
+
+ len = (exact_watchpoints
+ && is_scalar_type_recursive (vtype))?
+ 1 : TYPE_LENGTH (value_type (v));
- if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+ num_regs = target_region_ok_for_hw_watchpoint (vaddr, len);
+ if (!num_regs)
return 0;
else
- found_memory_cnt++;
+ found_memory_cnt += num_regs;
}
}
}
@@ -9025,6 +9083,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* resources_needed */
print_exception_catchpoint,
print_one_exception_catchpoint,
print_mention_exception_catchpoint,