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.
This commit is contained in:
parent
9fa40276f0
commit
e09342b536
|
@ -1,3 +1,45 @@
|
|||
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.
|
||||
* 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.
|
||||
|
||||
2011-01-11 Thiago Jung Bauermann <bauerman@br.ibm.com>
|
||||
|
||||
* breakpoint.c (update_watchpoint): Decide on using a software or
|
||||
|
|
|
@ -10901,6 +10901,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
|
|||
NULL, /* insert */
|
||||
NULL, /* remove */
|
||||
NULL, /* breakpoint_hit */
|
||||
NULL, /* resources_needed */
|
||||
print_it_catch_exception,
|
||||
print_one_catch_exception,
|
||||
print_mention_catch_exception,
|
||||
|
@ -10939,6 +10940,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
|
|||
NULL, /* insert */
|
||||
NULL, /* remove */
|
||||
NULL, /* breakpoint_hit */
|
||||
NULL, /* resources_needed */
|
||||
print_it_catch_exception_unhandled,
|
||||
print_one_catch_exception_unhandled,
|
||||
print_mention_catch_exception_unhandled,
|
||||
|
@ -10975,6 +10977,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
|
|||
NULL, /* insert */
|
||||
NULL, /* remove */
|
||||
NULL, /* breakpoint_hit */
|
||||
NULL, /* resources_needed */
|
||||
print_it_catch_assert,
|
||||
print_one_catch_assert,
|
||||
print_mention_catch_assert,
|
||||
|
|
135
gdb/breakpoint.c
135
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
|
|
@ -385,6 +385,11 @@ struct breakpoint_ops
|
|||
breakpoint was hit. */
|
||||
int (*breakpoint_hit) (struct breakpoint *);
|
||||
|
||||
/* Tell how many hardware resources (debug registers) are needed
|
||||
for this breakpoint. If this function is not provided, then
|
||||
the breakpoint or watchpoint needs one debug register. */
|
||||
int (*resources_needed) (const struct bp_location *);
|
||||
|
||||
/* The normal print routine for this breakpoint, called when we
|
||||
hit it. */
|
||||
enum print_stop_action (*print_it) (struct breakpoint *);
|
||||
|
@ -425,6 +430,13 @@ DEF_VEC_P(bp_location_p);
|
|||
detail to the breakpoints module. */
|
||||
struct counted_command_line;
|
||||
|
||||
/* Some targets (e.g., embedded PowerPC) need two debug registers to set
|
||||
a watchpoint over a memory region. If this flag is true, GDB will use
|
||||
only one register per watchpoint, thus assuming that all acesses that
|
||||
modify a memory location happen at its starting address. */
|
||||
|
||||
extern int target_exact_watchpoints;
|
||||
|
||||
/* Note that the ->silent field is not currently used by any commands
|
||||
(though the code is in there if it was to be, and set_raw_breakpoint
|
||||
does set it to 0). I implemented it because I thought it would be
|
||||
|
@ -595,7 +607,10 @@ struct breakpoint
|
|||
can sometimes be NULL for enabled GDBs as not all breakpoint
|
||||
types are tracked by the Python scripting API. */
|
||||
struct breakpoint_object *py_bp_object;
|
||||
};
|
||||
|
||||
/* Whether this watchpoint is exact (see target_exact_watchpoints). */
|
||||
int exact;
|
||||
};
|
||||
|
||||
typedef struct breakpoint *breakpoint_p;
|
||||
DEF_VEC_P(breakpoint_p);
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
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.texinfo (PowerPC Embedded): Document ranged watchpoints and
|
||||
the "set powerpc exact-watchpoints" flag.
|
||||
|
||||
2011-01-07 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.texinfo (Python API): Add descriptions to @menu items.
|
||||
|
@ -8,7 +15,7 @@
|
|||
|
||||
2010-01-06 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
* gdb.texinfo (Debugging Output): Document "set debug jit".
|
||||
* gdb.texinfo (Debugging Output): Document "set debug jit".
|
||||
|
||||
2011-01-06 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
|
|
|
@ -18721,9 +18721,25 @@ implement in hardware simple hardware watchpoint conditions of the form:
|
|||
if @var{ADDRESS|VARIABLE} == @var{CONSTANT EXPRESSION}
|
||||
@end smallexample
|
||||
|
||||
The DVC register will be automatically used whenever @value{GDBN} detects
|
||||
such pattern in a condition expression. This feature is available in native
|
||||
@value{GDBN} running on a Linux kernel version 2.6.34 or newer.
|
||||
The DVC register will be automatically used when @value{GDBN} detects
|
||||
such pattern in a condition expression, and the created watchpoint uses one
|
||||
debug register (either the @code{exact-watchpoints} option is on and the
|
||||
variable is scalar, or the variable has a length of one byte). This feature
|
||||
is available in native @value{GDBN} running on a Linux kernel version 2.6.34
|
||||
or newer.
|
||||
|
||||
When running on PowerPC embedded processors, @value{GDBN} automatically uses
|
||||
ranged hardware watchpoints, unless the @code{exact-watchpoints} option is on,
|
||||
in which case watchpoints using only one debug register are created when
|
||||
watching variables of scalar types.
|
||||
|
||||
You can create an artificial array to watch an arbitrary memory
|
||||
region using one of the following commands (@pxref{Expressions}):
|
||||
|
||||
@smallexample
|
||||
(@value{GDBP}) watch *((char *) @var{address})@@@var{length}
|
||||
(@value{GDBP}) watch @{char[@var{length}]@} @var{address}
|
||||
@end smallexample
|
||||
|
||||
@value{GDBN} provides the following PowerPC-specific commands:
|
||||
|
||||
|
@ -18744,6 +18760,12 @@ arguments and return values. The valid options are @samp{auto};
|
|||
registers. By default, @value{GDBN} selects the calling convention
|
||||
based on the selected architecture and the provided executable file.
|
||||
|
||||
@item set powerpc exact-watchpoints
|
||||
@itemx show powerpc exact-watchpoints
|
||||
Allow @value{GDBN} to use only one debug register when watching a variable
|
||||
of scalar type, thus assuming that the variable is accessed through the
|
||||
address of its first byte.
|
||||
|
||||
@kindex target dink32
|
||||
@item target dink32 @var{dev}
|
||||
DINK32 ROM monitor.
|
||||
|
|
|
@ -1955,6 +1955,68 @@ is_integral_type (struct type *t)
|
|||
|| (TYPE_CODE (t) == TYPE_CODE_BOOL)));
|
||||
}
|
||||
|
||||
/* Return true if TYPE is scalar. */
|
||||
|
||||
static int
|
||||
is_scalar_type (struct type *type)
|
||||
{
|
||||
CHECK_TYPEDEF (type);
|
||||
|
||||
switch (TYPE_CODE (type))
|
||||
{
|
||||
case TYPE_CODE_ARRAY:
|
||||
case TYPE_CODE_STRUCT:
|
||||
case TYPE_CODE_UNION:
|
||||
case TYPE_CODE_SET:
|
||||
case TYPE_CODE_STRING:
|
||||
case TYPE_CODE_BITSTRING:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if T is scalar, or a composite type which in practice has
|
||||
the memory layout of a scalar type. E.g., an array or struct with only one
|
||||
scalar element inside it, or a union with only scalar elements. */
|
||||
|
||||
int
|
||||
is_scalar_type_recursive (struct type *t)
|
||||
{
|
||||
CHECK_TYPEDEF (t);
|
||||
|
||||
if (is_scalar_type (t))
|
||||
return 1;
|
||||
/* Are we dealing with an array or string of known dimensions? */
|
||||
else if ((TYPE_CODE (t) == TYPE_CODE_ARRAY
|
||||
|| TYPE_CODE (t) == TYPE_CODE_STRING) && TYPE_NFIELDS (t) == 1
|
||||
&& TYPE_CODE (TYPE_INDEX_TYPE (t)) == TYPE_CODE_RANGE)
|
||||
{
|
||||
LONGEST low_bound, high_bound;
|
||||
struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (t));
|
||||
|
||||
get_discrete_bounds (TYPE_INDEX_TYPE (t), &low_bound, &high_bound);
|
||||
|
||||
return high_bound == low_bound && is_scalar_type_recursive (elt_type);
|
||||
}
|
||||
/* Are we dealing with a struct with one element? */
|
||||
else if (TYPE_CODE (t) == TYPE_CODE_STRUCT && TYPE_NFIELDS (t) == 1)
|
||||
return is_scalar_type_recursive (TYPE_FIELD_TYPE (t, 0));
|
||||
else if (TYPE_CODE (t) == TYPE_CODE_UNION)
|
||||
{
|
||||
int i, n = TYPE_NFIELDS (t);
|
||||
|
||||
/* If all elements of the union are scalar, then the union is scalar. */
|
||||
for (i = 0; i < n; i++)
|
||||
if (!is_scalar_type_recursive (TYPE_FIELD_TYPE (t, i)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A helper function which returns true if types A and B represent the
|
||||
"same" class type. This is true if the types have the same main
|
||||
type, or the same name. */
|
||||
|
|
|
@ -1476,6 +1476,8 @@ extern int can_dereference (struct type *);
|
|||
|
||||
extern int is_integral_type (struct type *);
|
||||
|
||||
extern int is_scalar_type_recursive (struct type *);
|
||||
|
||||
extern void maintenance_print_type (char *, int);
|
||||
|
||||
extern htab_t create_copied_types_hash (struct objfile *objfile);
|
||||
|
|
|
@ -1497,9 +1497,16 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
|
|||
to determine the hardcoded watchable region for watchpoints. */
|
||||
if (have_ptrace_booke_interface ())
|
||||
{
|
||||
if (booke_debug_info.data_bp_alignment
|
||||
&& (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
|
||||
+ booke_debug_info.data_bp_alignment))
|
||||
/* DAC-based processors (i.e., embedded processors), like the PowerPC 440
|
||||
have ranged watchpoints and can watch any access within an arbitrary
|
||||
memory region. This is useful to watch arrays and structs, for
|
||||
instance. It takes two hardware watchpoints though. */
|
||||
if (len > 1
|
||||
&& booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE)
|
||||
return 2;
|
||||
else if (booke_debug_info.data_bp_alignment
|
||||
&& (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
|
||||
+ booke_debug_info.data_bp_alignment))
|
||||
return 0;
|
||||
}
|
||||
/* addr+len must fall in the 8 byte watchable region for DABR-based
|
||||
|
@ -1889,6 +1896,55 @@ ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
|
|||
&& check_condition (addr, cond, &data_value));
|
||||
}
|
||||
|
||||
/* Set up P with the parameters necessary to request a watchpoint covering
|
||||
LEN bytes starting at ADDR and if possible with condition expression COND
|
||||
evaluated by hardware. INSERT tells if we are creating a request for
|
||||
inserting or removing the watchpoint. */
|
||||
|
||||
static void
|
||||
create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
|
||||
int len, int rw, struct expression *cond,
|
||||
int insert)
|
||||
{
|
||||
if (len == 1)
|
||||
{
|
||||
int use_condition;
|
||||
CORE_ADDR data_value;
|
||||
|
||||
use_condition = (insert? can_use_watchpoint_cond_accel ()
|
||||
: booke_debug_info.num_condition_regs > 0);
|
||||
if (cond && use_condition && check_condition (addr, cond, &data_value))
|
||||
calculate_dvc (addr, len, data_value, &p->condition_mode,
|
||||
&p->condition_value);
|
||||
else
|
||||
{
|
||||
p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
|
||||
p->condition_value = 0;
|
||||
}
|
||||
|
||||
p->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
|
||||
p->addr2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
|
||||
p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
|
||||
p->condition_value = 0;
|
||||
|
||||
/* The watchpoint will trigger if the address of the memory access is
|
||||
within the defined range, as follows: p->addr <= address < p->addr2.
|
||||
|
||||
Note that the above sentence just documents how ptrace interprets
|
||||
its arguments; the watchpoint is set to watch the range defined by
|
||||
the user _inclusively_, as specified by the user interface. */
|
||||
p->addr2 = (uint64_t) addr + len;
|
||||
}
|
||||
|
||||
p->version = PPC_DEBUG_CURRENT_VERSION;
|
||||
p->trigger_type = get_trigger_type (rw);
|
||||
p->addr = (uint64_t) addr;
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
|
||||
struct expression *cond)
|
||||
|
@ -1900,23 +1956,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
|
|||
if (have_ptrace_booke_interface ())
|
||||
{
|
||||
struct ppc_hw_breakpoint p;
|
||||
CORE_ADDR data_value;
|
||||
|
||||
if (cond && can_use_watchpoint_cond_accel ()
|
||||
&& check_condition (addr, cond, &data_value))
|
||||
calculate_dvc (addr, len, data_value, &p.condition_mode,
|
||||
&p.condition_value);
|
||||
else
|
||||
{
|
||||
p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
|
||||
p.condition_value = 0;
|
||||
}
|
||||
|
||||
p.version = PPC_DEBUG_CURRENT_VERSION;
|
||||
p.trigger_type = get_trigger_type (rw);
|
||||
p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
|
||||
p.addr = (uint64_t) addr;
|
||||
p.addr2 = 0;
|
||||
create_watchpoint_request (&p, addr, len, rw, cond, 1);
|
||||
|
||||
ALL_LWPS (lp, ptid)
|
||||
booke_insert_point (&p, TIDGET (ptid));
|
||||
|
@ -1984,23 +2025,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
|
|||
if (have_ptrace_booke_interface ())
|
||||
{
|
||||
struct ppc_hw_breakpoint p;
|
||||
CORE_ADDR data_value;
|
||||
|
||||
if (cond && booke_debug_info.num_condition_regs > 0
|
||||
&& check_condition (addr, cond, &data_value))
|
||||
calculate_dvc (addr, len, data_value, &p.condition_mode,
|
||||
&p.condition_value);
|
||||
else
|
||||
{
|
||||
p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
|
||||
p.condition_value = 0;
|
||||
}
|
||||
|
||||
p.version = PPC_DEBUG_CURRENT_VERSION;
|
||||
p.trigger_type = get_trigger_type (rw);
|
||||
p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
|
||||
p.addr = (uint64_t) addr;
|
||||
p.addr2 = 0;
|
||||
create_watchpoint_request (&p, addr, len, rw, cond, 0);
|
||||
|
||||
ALL_LWPS (lp, ptid)
|
||||
booke_remove_point (&p, TIDGET (ptid));
|
||||
|
|
|
@ -4183,6 +4183,16 @@ powerpc_set_vector_abi (char *args, int from_tty,
|
|||
internal_error (__FILE__, __LINE__, _("could not update architecture"));
|
||||
}
|
||||
|
||||
/* Show the current setting of the exact watchpoints flag. */
|
||||
|
||||
static void
|
||||
show_powerpc_exact_watchpoints (struct ui_file *file, int from_tty,
|
||||
struct cmd_list_element *c,
|
||||
const char *value)
|
||||
{
|
||||
fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value);
|
||||
}
|
||||
|
||||
/* Initialization code. */
|
||||
|
||||
/* -Wmissing-prototypes */
|
||||
|
@ -4240,4 +4250,17 @@ _initialize_rs6000_tdep (void)
|
|||
_("Show the vector ABI."),
|
||||
NULL, powerpc_set_vector_abi, NULL,
|
||||
&setpowerpccmdlist, &showpowerpccmdlist);
|
||||
|
||||
add_setshow_boolean_cmd ("exact-watchpoints", class_support,
|
||||
&target_exact_watchpoints,
|
||||
_("\
|
||||
Set whether to use just one debug register for watchpoints on scalars."),
|
||||
_("\
|
||||
Show whether to use just one debug register for watchpoints on scalars."),
|
||||
_("\
|
||||
If true, GDB will use only one debug register when watching a variable of\n\
|
||||
scalar type, thus assuming that the variable is accessed through the address\n\
|
||||
of its first byte."),
|
||||
NULL, show_powerpc_exact_watchpoints,
|
||||
&setpowerpccmdlist, &showpowerpccmdlist);
|
||||
}
|
||||
|
|
|
@ -453,7 +453,11 @@ struct target_ops
|
|||
int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
|
||||
int (*to_watchpoint_addr_within_range) (struct target_ops *,
|
||||
CORE_ADDR, CORE_ADDR, int);
|
||||
|
||||
/* Documentation of this routine is provided with the corresponding
|
||||
target_* macro. */
|
||||
int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
|
||||
|
||||
int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
|
||||
struct expression *);
|
||||
void (*to_terminal_init) (void);
|
||||
|
@ -1308,6 +1312,9 @@ extern char *normal_pid_to_str (ptid_t ptid);
|
|||
#define target_can_use_hardware_watchpoint(TYPE,CNT,OTHERTYPE) \
|
||||
(*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE);
|
||||
|
||||
/* Returns the number of debug registers needed to watch the given
|
||||
memory region, or zero if not supported. */
|
||||
|
||||
#define target_region_ok_for_hw_watchpoint(addr, len) \
|
||||
(*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
|
||||
|
||||
|
|
Loading…
Reference in New Issue