This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [patch 2/3] Implement support for PowerPC BookE ranged watchpoints
- From: Thiago Jung Bauermann <bauerman at br dot ibm dot com>
- To: Pedro Alves <pedro at codesourcery dot com>
- Cc: gdb-patches at sourceware dot org, Jan Kratochvil <jan dot kratochvil at redhat dot com>, Joel Brobecker <brobecker at adacore dot com>, Eli Zaretskii <eliz at gnu dot org>
- Date: Thu, 23 Dec 2010 16:49:42 -0200
- Subject: Re: [patch 2/3] Implement support for PowerPC BookE ranged watchpoints
- References: <1290549100.3164.47.camel@hactar> <201011251731.58135.pedro@codesourcery.com> <1290806122.3009.37.camel@hactar> <201011271747.39053.pedro@codesourcery.com>
Hi Pedro,
On Sat, 2010-11-27 at 17:47 +0000, Pedro Alves wrote:
> On Friday 26 November 2010 21:15:22, Thiago Jung Bauermann wrote:
> > Then comes the question of how to support the PPC_BREAKPOINT_MODE_EXACT
> > behaviour... A new flag or command to let the user "opt in" to a less
> > capable watchpoint, but one which uses less hardware resources?
>
> Yes, that's what I think we should do. I can help you code this,
> but I'm going computer-less real soon now until the 3rd December,
> and I'll only be able to help/review changes then onwards.
>
> Here's what I think we should do in more detail:
This patch implements your suggestions. The flag it adds is called "set
powerpc exact-watchpoints".
It applies on top of the "convert watchpoints to use breakpoint_ops"
patch (i.e., I changed the order of my patch series, now this patch
comes before the masked watchpoints patch).
There are no regressions on ppc-linux, ppc64-linux and i386-linux. Ok?
I had to make changes to the documentation, so it needs a doc review
too.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
2010-12-23 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) <extra_resources_needed>: New methods
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): Call breakpoint's
breakpoint_ops.extra_resources_needed if available.
(hw_watchpoint_used_count): Call breakpoint's
breakpoint_ops.extra_resources_needed if available. Change to
count number of bp_locations, instead of number of high-level
breakpoints.
(insert_watchpoint, remove_watchpoint): Use fixed length of 1 byte
if the watchpoint is exact.
(extra_resources_needed_watchpoint): New function.
(watchpoint_breakpoint_ops): Add extra_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): Accept 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, is_scalar_type_recursive): New functions.
* 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.
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 7ea01c7..3a2a266 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10821,6 +10821,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_it_catch_exception,
print_one_catch_exception,
print_mention_catch_exception,
@@ -10859,6 +10860,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_it_catch_exception_unhandled,
print_one_catch_exception_unhandled,
print_mention_catch_exception_unhandled,
@@ -10895,6 +10897,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_it_catch_assert,
print_one_catch_assert,
print_mention_catch_assert,
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 003899c..9c10b30 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);
@@ -345,6 +345,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. */
@@ -1394,25 +1397,33 @@ update_watchpoint (struct breakpoint *b, int reparse)
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)
+ int reg_cnt;
+
+ reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact);
+
+ if (!reg_cnt)
b->type = bp_watchpoint;
else
{
- int target_resources_ok = target_can_use_hardware_watchpoint
- (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+ int i, other_type_used, target_resources_ok;
+ enum bptype orig_type;
+
+ if (b->ops && b->ops->extra_resources_needed)
+ reg_cnt += b->ops->extra_resources_needed (b, NULL);
+
+ /* 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. */
+ orig_type = b->type;
+ b->type = bp_watchpoint;
+ i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+ &other_type_used);
+
+ target_resources_ok = target_can_use_hardware_watchpoint
+ (bp_hardware_watchpoint, i + reg_cnt, other_type_used)
if (target_resources_ok <= 0)
b->type = bp_watchpoint;
else
@@ -6004,6 +6015,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
insert_catch_fork,
remove_catch_fork,
breakpoint_hit_catch_fork,
+ NULL, /* extra_resources_needed */
print_it_catch_fork,
print_one_catch_fork,
print_mention_catch_fork,
@@ -6095,6 +6107,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
insert_catch_vfork,
remove_catch_vfork,
breakpoint_hit_catch_vfork,
+ NULL, /* extra_resources_needed */
print_it_catch_vfork,
print_one_catch_vfork,
print_mention_catch_vfork,
@@ -6376,6 +6389,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
insert_catch_syscall,
remove_catch_syscall,
breakpoint_hit_catch_syscall,
+ NULL, /* extra_resources_needed */
print_it_catch_syscall,
print_one_catch_syscall,
print_mention_catch_syscall,
@@ -6529,6 +6543,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
insert_catch_exec,
remove_catch_exec,
breakpoint_hit_catch_exec,
+ NULL, /* extra_resources_needed */
print_it_catch_exec,
print_one_catch_exec,
print_mention_catch_exec,
@@ -6570,19 +6585,29 @@ static int
hw_watchpoint_used_count (enum bptype type, int *other_type_used)
{
struct breakpoint *b;
+ struct bp_location *bl;
int i = 0;
*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)
+ {
+ i++;
+
+ /* Special types of hardware watchpoints may use more than
+ one register. */
+ if (b->ops && b->ops->extra_resources_needed)
+ i += b->ops->extra_resources_needed (b, bl);
+ }
else if (is_hardware_watchpoint (b))
*other_type_used = 1;
- }
- }
+ }
+
return i;
}
@@ -8119,8 +8144,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. */
@@ -8128,8 +8155,31 @@ 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 "extra_resources_needed" breakpoint_ops method for
+ hardware watchpoints. */
+
+static int
+extra_resources_needed_watchpoint (const struct breakpoint *b,
+ const struct bp_location *bl)
+{
+ if (bl)
+ {
+ int ret, length = bl->owner->exact? 1 : bl->length;
+
+ ret = target_region_ok_for_hw_watchpoint (bl->address, length);
+
+ gdb_assert (ret > 0);
+
+ return ret - 1;
+ }
+ else
+ return 0;
}
/* The breakpoint_ops structure to be used in hardware watchpoints. */
@@ -8139,6 +8189,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
insert_watchpoint,
remove_watchpoint,
NULL, /* breakpoint_hit */
+ extra_resources_needed_watchpoint,
NULL, /* print_it */
NULL, /* print_one */
NULL, /* print_mention */
@@ -8165,7 +8216,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;
@@ -8300,14 +8351,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."));
@@ -8318,7 +8369,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);
@@ -8389,6 +8440,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
b->val_valid = 1;
b->ops = &watchpoint_breakpoint_ops;
+ /* Use an exact watchpoint only when there's one memory region to be
+ watched, which needs only one debug register. */
+ b->exact = target_exact_watchpoints && reg_cnt == 1;
+
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
@@ -8428,12 +8483,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 need 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 can not 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;
@@ -8486,12 +8544,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;
}
}
}
@@ -8915,6 +8979,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_exception_catchpoint,
print_one_exception_catchpoint,
print_mention_exception_catchpoint,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 12c2df2..8e68532 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -372,6 +372,16 @@ struct breakpoint_ops
breakpoint was hit. */
int (*breakpoint_hit) (struct breakpoint *);
+ /* Tell how many additional hardware resources (debug registers) are needed
+ for this breakpoint. The bp_location argument may be NULL if the method
+ is called at a point where no location is assigned to the breakpoint yet.
+
+ We always count at least one resource, so if this function returns 1, then
+ GDB will consider that the breakpoint needes 2 registers. If this element
+ is NULL, then no additional resources are needed. */
+ int (*extra_resources_needed) (const struct breakpoint *,
+ const struct bp_location *);
+
/* The normal print routine for this breakpoint, called when we
hit it. */
enum print_stop_action (*print_it) (struct breakpoint *);
@@ -411,6 +421,13 @@ DEF_VEC_P(bp_location_p);
detail to the breakpoints module. */
struct counted_command_line;
+/* Some targets (eg, 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
@@ -577,7 +594,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);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0e1d553..cef320e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18728,9 +18728,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:
@@ -18751,6 +18767,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 all acesses that modify that variable
+happen at its starting address.
+
@kindex target dink32
@item target dink32 @var{dev}
DINK32 ROM monitor.
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index b651098..4e48d06 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1955,6 +1955,49 @@ is_integral_type (struct type *t)
|| (TYPE_CODE (t) == TYPE_CODE_BOOL)));
}
+static int
+is_scalar_type (struct type *t)
+{
+ CHECK_TYPEDEF (t);
+ return (is_integral_type (t) || ((t != NULL)
+ && (TYPE_CODE (t) == TYPE_CODE_FLT)));
+}
+
+int
+is_scalar_type_recursive (struct type *t)
+{
+ CHECK_TYPEDEF (t);
+
+ if (is_scalar_type (t))
+ return 1;
+ 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);
+ }
+ 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. */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 1ce2d91..3d27bb4 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1475,6 +1475,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);
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 18ddee7..7c853a9 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1489,9 +1489,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
@@ -1878,6 +1885,51 @@ 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. */
+
+static void
+create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
+ int len, int rw, struct expression *cond)
+{
+ if (len == 1)
+ {
+ 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->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)
@@ -1889,23 +1941,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);
ALL_LWPS (lp, ptid)
booke_insert_point (&p, TIDGET (ptid));
@@ -1973,23 +2010,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);
ALL_LWPS (lp, ptid)
booke_remove_point (&p, TIDGET (ptid));
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 81a99b6..1152d04 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -4177,6 +4177,15 @@ powerpc_set_vector_abi (char *args, int from_tty,
internal_error (__FILE__, __LINE__, "could not update architecture");
}
+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 just one debug register per watchpoint is %s.\n"), value);
+}
+
/* Initialization code. */
extern initialize_file_ftype _initialize_rs6000_tdep; /* -Wmissing-prototypes */
@@ -4233,4 +4242,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 per watchpoint."),
+ _("\
+Show whether to use just one debug register per watchpoint."),
+ _("\
+If true, GDB will use only one debug register when watching a variable of\n\
+scalar type, thus assuming that all acesses that modify that variable happen\n\
+at its starting address."),
+ NULL, show_powerpc_exact_watchpoints,
+ &setpowerpccmdlist, &showpowerpccmdlist);
}
diff --git a/gdb/target.h b/gdb/target.h
index bc70107..2ef5c56 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -452,7 +452,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);
@@ -1313,6 +1317,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)