[patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints

Thiago Jung Bauermann
2010-08-17T19:42:16Z

Adds support for the following types of watchpoints:

* Range Hardware Watchpoints: Monitors accesses to an interval of data
addresses. For BookE processors, a single Range Hardware
Watchpoint can be used provided that no Simple/Mask watchpoints are
being used.

Available GDB commands:

watch-range <address1>, <address2>
watch-range <address1>, +<length>

Similarly for awatch-range and rwatch-range.

Examples:
watch-range &i, &k
awatch-range 0xbffff8e8, 0xbffff8f8
rwatch-range 0xbffff8e8, +8

(gdb) watch-range 0x10094354,+79
Ranged hardware watchpoint 4: range: [0x10094354, 0x100943a2]
(gdb) info breakpoints
Num Type Disp Enb Address What
4 hw watchpoint keep y range: [0x10094354, 0x100943a2]

Also, when the user adds a watchpoint to a structure or array, GDB
will see if it can automatically set a ranged watchpoint instead:

(gdb) ptype b
type = char [79]
(gdb) watch b
Ranged hardware watchpoint 2: b
(gdb) info breakpoints
Num Type Disp Enb Address What
2 hw watchpoint keep y b
memory range: [0x10094354, 0x100943a2]

* Mask Hardware Watchpoints: Monitors accesses to data addresses that
match a specific pattern. For BookE processors, a single Mask
Hardware Watchpoint can be used provided that no Simple/Range
watchpoints are being used. Due to the processor's design, the
precise data address of the watchpoint trigger is not available, so
the user must check the instruction that caused the trigger
(usually at PC - 4) to obtain such data address. With such data
address in hand, it's possible to tell if its contents have changed.

Available GDB commands:

watch <variable | address> mask <mask_value>

Similarly for awatch-range and rwatch-range.

Examples:

watch i mask 0xffffff00
awatch *0xbffff8e8 mask 0xffffff00

(gdb) watch a mask 0xffffff00
Masked hardware watchpoint 5: a
(gdb) info breakpoints
Num Type Disp Enb Address What
5 hw watchpoint keep y a
mask 0xffffff00

Since the Simple/Range/Mask Hardware Watchpoints share the same register
set, the allowed combinations are as follows:

- 2 Simple Hardware Watchpoints with/without data value check
- 1 Range Hardware Watchpoint
- 1 Mask Hardware Watchpoint

I could have added a "range" parameter to the watchpoint command instead
of creating a new watch-range command. I don't have a real preference
except. The watch-range command has a slight advantage in that the
syntax used to specify a range is the same already used by the find
command, whereas the other option would be non-standard:

watch <address1> range <address2>
watch <address1> range +<length>

Also, Joel made a comment about this patch:

> In this instance as well, I would like to see if we could push all
> the logic to the target, by providing all the information the target
> needs in order to make that decision.
>
> One nice upside is that this will allow the target to use both range
> watchpoint and condition hardware acceleration if the target allows
> it.
> Or if it doesn't, not separating the two types of features with
> separate target watchpoint_insert/remove routines allows the target
> to choose which one makes most sense if a choice needs to be made.

I prefer to keep the generic GDB code aware of these types of
watchpoints for some reasons:

- I think it's important that GDB reports to the user which type of
watchpoint was created.
- The user should be able to explicitly create a ranged watchpoint.
- Ditto for masked watchpoints. I don't see how we could automatically
create those.
- These new types of watchpoints consume 2 debug registers each, so
there would still have to be some special handling of those when
counting available hardware resources to see if there's space for one
more hardware watchpoint (probably new bptypes, but that would mean
many changes to make these bptypes be handled across GDB, making the
patch more invasive than this one).

The hunks which change the parsing of parameters in watch_command_1 are
a bit confusing in the diff because of the indentation changes, so I
post below the same hunks without considering whitespace. This makes it
clear what really changed in the code.

Tested on ppc-linux, ppc64-linux and i686-linux with no regressions.
Ok?

===== start of diff ignoring whitespace =====

@@ -8052,8 +8423,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
struct frame_info *frame;
char *exp_start = NULL;
char *exp_end = NULL;
- char *tok, *id_tok_start, *end_tok;
- int toklen;
+ char *tok, *end_tok;
+ int toklen = -1;
char *cond_start = NULL;
char *cond_end = NULL;
int i, other_type_used, target_resources_ok = 0;
@@ -8061,64 +8432,96 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
int mem_cnt = 0;
int thread = -1;
int pc = 0;
+ /* Flag to indicate whether we are going to use masks for
+ the hardware watchpoint. */
+ int use_mask = 0;
+ CORE_ADDR hw_wp_mask = 0;
+ /* Whether we are watching an array or struct and hence we will
+ try to use ranged hardware watchpoints, if available. */
+ int use_ranged = 0;

/* Make sure that we actually have parameters to parse. */
if (arg != NULL && arg[0] != '\0')
{
- toklen = strlen (arg); /* Size of argument list. */
-
- /* Points tok to the end of the argument list. */
- tok = arg + toklen - 1;
+ char *value_start;

- /* Go backwards in the parameters list. Skip the last parameter.
- If we're expecting a 'thread <thread_num>' parameter, this should
- be the thread identifier. */
+ /* Look for "parameter value" pairs at the end
+ of the arguments string. */
+ for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+ {
+ /* Skip whitespace at the end of the argument list. */
while (tok > arg && (*tok == ' ' || *tok == '\t'))
tok--;
+
+ /* Find the beginning of the last token.
+ This is the value of the parameter. */
while (tok > arg && (*tok != ' ' && *tok != '\t'))
tok--;
+ value_start = tok + 1;

- /* Points end_tok to the beginning of the last token. */
- id_tok_start = tok + 1;
-
- /* Go backwards in the parameters list. Skip one more parameter.
- If we're expecting a 'thread <thread_num>' parameter, we should
- reach a "thread" token. */
+ /* Skip whitespace. */
while (tok > arg && (*tok == ' ' || *tok == '\t'))
tok--;

end_tok = tok;

+ /* Find the beginning of the second to last token.
+ This is the parameter itself. */
while (tok > arg && (*tok != ' ' && *tok != '\t'))
tok--;
-
- /* Move the pointer forward to skip the whitespace and
- calculate the length of the token. */
tok++;
- toklen = end_tok - tok;
+ toklen = end_tok - tok + 1;

- if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+ if (toklen == 6 && !strncmp (tok, "thread", 6))
{
/* At this point we've found a "thread" token, which means
the user is trying to set a watchpoint that triggers
only in a specific thread. */
char *endp;

+ if (thread != -1)
+ error(_("You can specify only one thread."));
+
/* Extract the thread ID from the next token. */
- thread = strtol (id_tok_start, &endp, 0);
+ thread = strtol (value_start, &endp, 0);

/* Check if the user provided a valid numeric value for the
thread ID. */
if (*endp != ' ' && *endp != '\t' && *endp != '\0')
- error (_("Invalid thread ID specification %s."), id_tok_start);
+ error (_("Invalid thread ID specification %s."), value_start);

/* Check if the thread actually exists. */
if (!valid_thread_id (thread))
error (_("Unknown thread %d."), thread);
+ }
+ else if (toklen == 4 && !strncmp (tok, "mask", 4))
+ {
+ /* We've found a "mask" token, which means the user wants to
+ create a hardware watchpoint that is going to have the mask
+ facility. */
+ struct value *mask_value, *mark;
+
+ /* Does the target support masked watchpoints? */
+ if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+ error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
+
+ if (use_mask)
+ error(_("You can specify only one mask."));
+
+ use_mask = 1;

- /* Truncate the string and get rid of the thread <thread_num>
- parameter before the parameter list is parsed by the
- evaluate_expression() function. */
+ mark = value_mark ();
+ mask_value = parse_to_comma_and_eval (&value_start);
+ hw_wp_mask = value_as_address (mask_value);
+ value_free_to_mark (mark);
+ }
+ else
+ /* We didn't recognize what we found. We should stop here. */
+ break;
+
+ /* Truncate the string and get rid of the "parameter value" pair before
+ the arguments string is parsed by the parse_exp_1 function. */
*tok = '\0';
}
}

===== end of diff ignoring whitespace =====

--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

2010-08-17 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>

Implement support for PowerPC BookE masked and ranged watchpoints.

gdb/
* breakpoint.c (update_watchpoint): Call breakpoint's
breakpoint_ops.extra_resources_needed if available.
(watchpoints_triggered): Handle the case of a hardware masked
watchpoint trigger.
(watchpoint_check): Handle the case of a hardware masked watchpoint
trigger.
(print_one_breakpoint_location): Call breakpoint's
breakpoint_ops.print_one_detail if available.
(hw_watchpoint_used_count): Call breakpoint's
breakpoint_ops.extra_resources_needed if available.
(insert_ranged_watchpoint, remove_ranged_watchpoint)
(extra_resources_needed_ranged_watchpoint)
(print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint)
(print_recreate_ranged_watchpoint): New functions.
(ranged_watchpoint_breakpoint_ops): New structure.
(insert_masked_watchpoint, remove_masked_watchpoint)
(extra_resources_needed_masked_watchpoint, print_it_masked_watchpoint)
(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
(print_recreate_masked_watchpoint, is_masked_watchpoint): New functions.
(masked_watchpoint_breakpoint_ops): New structure.
(watch_command_1): Check for the existence of the `mask' parameter.
Check whether a ranged hardware watchpoint can be used. Set b->ops
according to the type of hardware watchpoint being created.
(watch_range_command_1): New function.
(watch_range_command): Ditto.
(awatch_range_command): Ditto.
(rwatch_range_command): Ditto.
(_initialize_breakpoint): Register watch-range, awatch-range and
rwatch-range commands.
* breakpoint.h (struct breakpoint_ops) <extra_resources_needed>,
<print_one_detail>: New methods. Initialize them to NULL in all
existing breakpoint_ops instances.
(struct breakpoint_ops) <print_stop_action>: Add OLD_VAL parameter.
Update all implementations of the method.
(enum hw_point_flag): New enumeration.
(struct breakpoint) <hw_wp_mask>: New field.
* findcmd.c (parse_addr_range): New function.
(parse_find_args): Call `parse_addr_range'.
* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function.
(ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when
ranged watchpoints are available.
(ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint)
(ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint)
(ppc_linux_hw_point_extra_slot_count): New functions.
(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
to_remove_ranged_watchpoint, hw_point_extra_slot_count and
to_can_use_special_hw_point.
* target.c (update_current_target): Insert to_insert_mask_watchpoint,
to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
to_remove_ranged_watchpoint, to_hw_point_extra_slot_count
and to_can_use_special_hw_point.
* target.h (enum hw_point_flag): New opaque declaration.
(struct target_ops) <to_insert_mask_watchpoint>,
<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
<to_remove_ranged_watchpoint>, <to_hw_point_extra_slot_count>,
<to_can_use_special_hw_point>: New callbacks.
(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
(target_hw_point_extra_slot_count, target_can_use_special_hw_point): New
defines.
* ui-out.c (ui_out_field_range_core_addr): New function.
* ui-out.h (ui_out_field_range_core_addr): Declare.
* value.h (parse_addr_range): Declare.

gdb/doc/
* gdb.texinfo (Set Watchpoints): Document mask parameter.
(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.

Index: gdb.git/gdb/ada-lang.c
===================================================================
--- gdb.git.orig/gdb/ada-lang.c 2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ada-lang.c 2010-08-17 12:31:28.000000000 -0300
@@ -10620,7 +10620,7 @@ print_recreate_exception (enum exception
/* Virtual table for "catch exception" breakpoints. */

static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
{
return print_it_exception (ex_catch_exception, b);
}
@@ -10648,8 +10648,10 @@ static struct breakpoint_ops catch_excep
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_it_catch_exception,
print_one_catch_exception,
+ NULL, /* print_one_detail */
print_mention_catch_exception,
print_recreate_catch_exception
};
@@ -10657,7 +10659,8 @@ static struct breakpoint_ops catch_excep
/* Virtual table for "catch exception unhandled" breakpoints. */

static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+ const struct value *old_val)
{
return print_it_exception (ex_catch_exception_unhandled, b);
}
@@ -10686,8 +10689,10 @@ static struct breakpoint_ops catch_excep
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_it_catch_exception_unhandled,
print_one_catch_exception_unhandled,
+ NULL, /* print_one_detail */
print_mention_catch_exception_unhandled,
print_recreate_catch_exception_unhandled
};
@@ -10695,7 +10700,7 @@ static struct breakpoint_ops catch_excep
/* Virtual table for "catch assert" breakpoints. */

static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
{
return print_it_exception (ex_catch_assert, b);
}
@@ -10722,8 +10727,10 @@ static struct breakpoint_ops catch_asser
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_it_catch_assert,
print_one_catch_assert,
+ NULL, /* print_one_detail */
print_mention_catch_assert,
print_recreate_catch_assert
};
Index: gdb.git/gdb/breakpoint.c
===================================================================
--- gdb.git.orig/gdb/breakpoint.c 2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/breakpoint.c 2010-08-17 12:31:28.000000000 -0300
@@ -222,6 +222,8 @@ static void disable_trace_command (char

static void trace_pass_command (char *, int);

+static int is_masked_watchpoint (const struct breakpoint *b);
+
/* Assuming we're creating a static tracepoint, does S look like a
static tracepoint marker spec ("-m MARKER_ID")? */
#define is_marker_spec(s) \
@@ -1422,8 +1424,15 @@ update_watchpoint (struct breakpoint *b,
}
else
{
- int target_resources_ok = target_can_use_hardware_watchpoint
- (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+ int target_resources_ok;
+
+ if (b->ops && b->ops->extra_resources_needed)
+ mem_cnt += b->ops->extra_resources_needed (b);
+ else if (b->old_ops && b->old_ops->extra_resources_needed)
+ mem_cnt += b->old_ops->extra_resources_needed (b);
+
+ 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;
@@ -3379,7 +3388,7 @@ print_bp_stop_message (bpstat bs)
print_it_typical. */
/* FIXME: how breakpoint can ever be NULL here? */
if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
- return b->ops->print_it (b);
+ return b->ops->print_it (b, bs->old_val);
else
return print_it_typical (bs);
}
@@ -3511,15 +3520,30 @@ watchpoints_triggered (struct target_wai

b->watchpoint_triggered = watch_triggered_no;
for (loc = b->loc; loc; loc = loc->next)
- /* Exact match not required. Within range is
- sufficient. */
- if (target_watchpoint_addr_within_range (&current_target,
- addr, loc->address,
- loc->length))
- {
- b->watchpoint_triggered = watch_triggered_yes;
- break;
- }
+ {
+ CORE_ADDR newaddr, start;
+
+ if (is_masked_watchpoint (loc->owner))
+ {
+ newaddr = addr & loc->owner->hw_wp_mask;
+ start = loc->address & loc->owner->hw_wp_mask;
+ }
+ else
+ {
+ newaddr = addr;
+ start = loc->address;
+ }
+
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (target_watchpoint_addr_within_range (&current_target,
+ newaddr, start,
+ loc->length))
+ {
+ b->watchpoint_triggered = watch_triggered_yes;
+ break;
+ }
+ }
}

return 1;
@@ -3634,6 +3658,11 @@ watchpoint_check (void *p)
b->val_valid = 1;
return WP_VALUE_CHANGED;
}
+ else if (is_masked_watchpoint (b))
+ /* Since we don't know the exact trigger address (from
+ stopped_data_address) Just tell the user we've triggered
+ a mask watchpoint. */
+ return WP_VALUE_CHANGED;
else
{
/* Nothing changed. */
@@ -4688,9 +4717,12 @@ print_one_breakpoint_location (struct br
ui_out_field_int (uiout, "task", b->task);
}
}
-
+
ui_out_text (uiout, "\n");
-
+
+ if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+ b->ops->print_one_detail (b, uiout);
+
if (!part_of_multiple && b->static_trace_marker_id)
{
gdb_assert (b->type == bp_static_tracepoint);
@@ -5851,7 +5883,7 @@ breakpoint_hit_catch_fork (struct breakp
/* Implement the "print_it" breakpoint_ops method for fork catchpoints. */

static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
{
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -5909,8 +5941,10 @@ static struct breakpoint_ops catch_fork_
insert_catch_fork,
remove_catch_fork,
breakpoint_hit_catch_fork,
+ NULL, /* extra_resources_needed */
print_it_catch_fork,
print_one_catch_fork,
+ NULL, /* print_one_detail */
print_mention_catch_fork,
print_recreate_catch_fork
};
@@ -5943,7 +5977,7 @@ breakpoint_hit_catch_vfork (struct break
/* Implement the "print_it" breakpoint_ops method for vfork catchpoints. */

static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
{
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6000,8 +6034,10 @@ static struct breakpoint_ops catch_vfork
insert_catch_vfork,
remove_catch_vfork,
breakpoint_hit_catch_vfork,
+ NULL, /* extra_resources_needed */
print_it_catch_vfork,
print_one_catch_vfork,
+ NULL, /* print_one_detail */
print_mention_catch_vfork,
print_recreate_catch_vfork
};
@@ -6121,7 +6157,7 @@ breakpoint_hit_catch_syscall (struct bre
catchpoints. */

static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
{
/* These are needed because we want to know in which state a
syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6281,8 +6317,10 @@ static struct breakpoint_ops catch_sysca
insert_catch_syscall,
remove_catch_syscall,
breakpoint_hit_catch_syscall,
+ NULL, /* extra_resources_needed */
print_it_catch_syscall,
print_one_catch_syscall,
+ NULL, /* print_one_detail */
print_mention_catch_syscall,
print_recreate_catch_syscall
};
@@ -6384,7 +6422,7 @@ breakpoint_hit_catch_exec (struct breakp
}

static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
{
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6434,8 +6472,10 @@ static struct breakpoint_ops catch_exec_
insert_catch_exec,
remove_catch_exec,
breakpoint_hit_catch_exec,
+ NULL, /* extra_resources_needed */
print_it_catch_exec,
print_one_catch_exec,
+ NULL, /* print_one_detail */
print_mention_catch_exec,
print_recreate_catch_exec
};
@@ -6483,7 +6523,14 @@ hw_watchpoint_used_count (enum bptype ty
if (breakpoint_enabled (b))
{
if (b->type == type)
- i++;
+ {
+ i++;
+
+ /* Special types of hardware watchpoints can use more than
+ one register. */
+ if (b->ops && b->ops->extra_resources_needed)
+ i += b->ops->extra_resources_needed (b);
+ }
else if (is_hardware_watchpoint (b))
*other_type_used = 1;
}
@@ -8025,12 +8072,336 @@ static struct breakpoint_ops watchpoint_
insert_watchpoint,
remove_watchpoint,
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
NULL, /* print_it */
NULL, /* print_one */
+ NULL, /* print_one_detail */
NULL, /* print_mention */
NULL /* print_recreate */
};

+/* Implement the "insert" breakpoint_ops method for
+ ranged hardware watchpoints. */
+
+static int
+insert_ranged_watchpoint (struct bp_location *bpt)
+{
+ return target_insert_ranged_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+ ranged hardware watchpoints. */
+
+static int
+remove_ranged_watchpoint (struct bp_location *bpt)
+{
+ return target_remove_ranged_watchpoint (bpt->address, bpt->length,
+ bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+ ranged hardware watchpoints. */
+
+static int
+extra_resources_needed_ranged_watchpoint (const struct breakpoint *b)
+{
+ return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+ ranged hardware watchpoints. */
+
+static void
+print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+ /* If there's a separate expression for reparsing, then exp_string is already
+ a nice text set by watch_range_command_1 and was printed earlier. */
+ if (b->exp_string_reparse)
+ return;
+
+ gdb_assert (b->loc);
+
+ ui_out_text (uiout, "\tmemory range: ");
+ ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+ b->loc->address, b->loc->length);
+ ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+ ranged hardware watchpoints. */
+
+static void
+print_mention_ranged_watchpoint (struct breakpoint *b)
+{
+ struct cleanup *ui_out_chain;
+
+ switch (b->type)
+ {
+ case bp_hardware_watchpoint:
+ ui_out_text (uiout, "Ranged hardware watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+ break;
+ case bp_read_watchpoint:
+ ui_out_text (uiout, "Ranged hardware read watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+ break;
+ case bp_access_watchpoint:
+ ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Invalid hardware watchpoint type."));
+ }
+
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ ui_out_field_string (uiout, "exp", b->exp_string);
+ do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+ switch (b->type)
+ {
+ case bp_hardware_watchpoint:
+ if (b->exp_string_reparse)
+ fprintf_unfiltered (fp, "watch-range");
+ else
+ fprintf_unfiltered (fp, "watch");
+ break;
+ case bp_read_watchpoint:
+ if (b->exp_string_reparse)
+ fprintf_unfiltered (fp, "rwatch-range");
+ else
+ fprintf_unfiltered (fp, "rwatch");
+ break;
+ case bp_access_watchpoint:
+ if (b->exp_string_reparse)
+ fprintf_unfiltered (fp, "awatch-range");
+ else
+ fprintf_unfiltered (fp, "awatch");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Invalid hardware watchpoint type."));
+ }
+
+ if (b->exp_string_reparse)
+ {
+ char start_addr[40], length[40];
+
+ /* watch_range_command_1 creates the following expression to represent
+ internally a ranged watchpoint. */
+ sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr);
+
+ fprintf_unfiltered (fp, " %s, +%s", start_addr, length);
+ }
+ else
+ fprintf_unfiltered (fp, " %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged hardware watchpoints. */
+
+static struct breakpoint_ops ranged_watchpoint_breakpoint_ops =
+{
+ insert_ranged_watchpoint,
+ remove_ranged_watchpoint,
+ NULL, /* breakpoint_hit */
+ extra_resources_needed_ranged_watchpoint,
+ NULL, /* print_it */
+ NULL, /* print_one */
+ print_one_detail_ranged_watchpoint,
+ print_mention_ranged_watchpoint,
+ print_recreate_ranged_watchpoint
+};
+
+/* Implement the "insert" breakpoint_ops method for
+ masked hardware watchpoints. */
+
+static int
+insert_masked_watchpoint (struct bp_location *bpt)
+{
+ return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+ bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+ masked hardware watchpoints. */
+
+static int
+remove_masked_watchpoint (struct bp_location *bpt)
+{
+ return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+ bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+ masked hardware watchpoints. */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b)
+{
+ return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+ masked hardware watchpoints. */
+
+enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val)
+{
+ struct ui_stream *stb;
+ struct cleanup *old_chain;
+
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+ switch (b->type)
+ {
+ case bp_hardware_watchpoint:
+ annotate_watchpoint (b->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+ break;
+
+ case bp_read_watchpoint:
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+ break;
+
+ case bp_access_watchpoint:
+ if (old_val != NULL)
+ {
+ annotate_watchpoint (b->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+ }
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Invalid hardware watchpoint type."));
+ }
+
+ mention (b);
+ ui_out_text (uiout, "\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n");
+ ui_out_text (uiout, "\n");
+
+ do_cleanups (old_chain);
+
+ /* More than one watchpoint may have been triggered. */
+ return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+ masked hardware watchpoints. */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+ ui_out_text (uiout, "\tmask ");
+
+ /* I don't know whether it's possible to get here without a b->loc,
+ but we can handle the situation. */
+ if (b->loc)
+ ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+ else
+ ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+ ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+ masked hardware watchpoints. */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+ struct cleanup *ui_out_chain;
+
+ switch (b->type)
+ {
+ case bp_hardware_watchpoint:
+ ui_out_text (uiout, "Masked hardware watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+ break;
+ case bp_read_watchpoint:
+ ui_out_text (uiout, "Masked hardware read watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+ break;
+ case bp_access_watchpoint:
+ ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Invalid hardware watchpoint type."));
+ }
+
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ ui_out_field_string (uiout, "exp", b->exp_string);
+ do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+ char tmp[40];
+
+ switch (b->type)
+ {
+ case bp_hardware_watchpoint:
+ fprintf_unfiltered (fp, "watch");
+ break;
+ case bp_read_watchpoint:
+ fprintf_unfiltered (fp, "rwatch");
+ break;
+ case bp_access_watchpoint:
+ fprintf_unfiltered (fp, "awatch");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Invalid hardware watchpoint type."));
+ }
+
+ sprintf_vma (tmp, b->hw_wp_mask);
+ fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints. */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+ insert_masked_watchpoint,
+ remove_masked_watchpoint,
+ NULL, /* breakpoint_hit */
+ extra_resources_needed_masked_watchpoint,
+ print_it_masked_watchpoint,
+ NULL, /* print_one */
+ print_one_detail_masked_watchpoint,
+ print_mention_masked_watchpoint,
+ print_recreate_masked_watchpoint
+};
+
+/* Tells whether the given watchpoint is a masked hardware watchpoint. */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+ return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
/* accessflag: hw_write: watch write,
hw_read: watch read,
hw_access: watch access (read or write) */
@@ -8044,8 +8415,8 @@ watch_command_1 (char *arg, int accessfl
struct frame_info *frame;
char *exp_start = NULL;
char *exp_end = NULL;
- char *tok, *id_tok_start, *end_tok;
- int toklen;
+ char *tok, *end_tok;
+ int toklen = -1;
char *cond_start = NULL;
char *cond_end = NULL;
int i, other_type_used, target_resources_ok = 0;
@@ -8053,66 +8424,98 @@ watch_command_1 (char *arg, int accessfl
int mem_cnt = 0;
int thread = -1;
int pc = 0;
+ /* Flag to indicate whether we are going to use masks for
+ the hardware watchpoint. */
+ int use_mask = 0;
+ CORE_ADDR hw_wp_mask = 0;
+ /* Whether we are watching an array or struct and hence we will
+ try to use ranged hardware watchpoints, if available. */
+ int use_ranged = 0;

/* Make sure that we actually have parameters to parse. */
if (arg != NULL && arg[0] != '\0')
{
- toklen = strlen (arg); /* Size of argument list. */
+ char *value_start;

- /* Points tok to the end of the argument list. */
- tok = arg + toklen - 1;
+ /* Look for "parameter value" pairs at the end
+ of the arguments string. */
+ for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+ {
+ /* Skip whitespace at the end of the argument list. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;
+
+ /* Find the beginning of the last token.
+ This is the value of the parameter. */
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;
+ value_start = tok + 1;
+
+ /* Skip whitespace. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;
+
+ end_tok = tok;
+
+ /* Find the beginning of the second to last token.
+ This is the parameter itself. */
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;
+ tok++;
+ toklen = end_tok - tok + 1;
+
+ if (toklen == 6 && !strncmp (tok, "thread", 6))
+ {
+ /* At this point we've found a "thread" token, which means
+ the user is trying to set a watchpoint that triggers
+ only in a specific thread. */
+ char *endp;
+
+ if (thread != -1)
+ error(_("You can specify only one thread."));
+
+ /* Extract the thread ID from the next token. */
+ thread = strtol (value_start, &endp, 0);
+
+ /* Check if the user provided a valid numeric value for the
+ thread ID. */
+ if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+ error (_("Invalid thread ID specification %s."), value_start);
+
+ /* Check if the thread actually exists. */
+ if (!valid_thread_id (thread))
+ error (_("Unknown thread %d."), thread);
+ }
+ else if (toklen == 4 && !strncmp (tok, "mask", 4))
+ {
+ /* We've found a "mask" token, which means the user wants to
+ create a hardware watchpoint that is going to have the mask
+ facility. */
+ struct value *mask_value, *mark;

- /* Go backwards in the parameters list. Skip the last parameter.
- If we're expecting a 'thread <thread_num>' parameter, this should
- be the thread identifier. */
- while (tok > arg && (*tok == ' ' || *tok == '\t'))
- tok--;
- while (tok > arg && (*tok != ' ' && *tok != '\t'))
- tok--;
-
- /* Points end_tok to the beginning of the last token. */
- id_tok_start = tok + 1;
-
- /* Go backwards in the parameters list. Skip one more parameter.
- If we're expecting a 'thread <thread_num>' parameter, we should
- reach a "thread" token. */
- while (tok > arg && (*tok == ' ' || *tok == '\t'))
- tok--;
+ /* Does the target support masked watchpoints? */
+ if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+ error (_("\
+This target does not support the usage of masks with hardware watchpoints."));

- end_tok = tok;
+ if (use_mask)
+ error(_("You can specify only one mask."));

- while (tok > arg && (*tok != ' ' && *tok != '\t'))
- tok--;
+ use_mask = 1;

- /* Move the pointer forward to skip the whitespace and
- calculate the length of the token. */
- tok++;
- toklen = end_tok - tok;
+ mark = value_mark ();
+ mask_value = parse_to_comma_and_eval (&value_start);
+ hw_wp_mask = value_as_address (mask_value);
+ value_free_to_mark (mark);
+ }
+ else
+ /* We didn't recognize what we found. We should stop here. */
+ break;

- if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
- {
- /* At this point we've found a "thread" token, which means
- the user is trying to set a watchpoint that triggers
- only in a specific thread. */
- char *endp;
-
- /* Extract the thread ID from the next token. */
- thread = strtol (id_tok_start, &endp, 0);
-
- /* Check if the user provided a valid numeric value for the
- thread ID. */
- if (*endp != ' ' && *endp != '\t' && *endp != '\0')
- error (_("Invalid thread ID specification %s."), id_tok_start);
-
- /* Check if the thread actually exists. */
- if (!valid_thread_id (thread))
- error (_("Unknown thread %d."), thread);
-
- /* Truncate the string and get rid of the thread <thread_num>
- parameter before the parameter list is parsed by the
- evaluate_expression() function. */
- *tok = '\0';
- }
+ /* Truncate the string and get rid of the "parameter value" pair before
+ the arguments string is parsed by the parse_exp_1 function. */
+ *tok = '\0';
+ }
}

/* Parse the rest of the arguments. */
@@ -8190,6 +8593,22 @@ watch_command_1 (char *arg, int accessfl
error (_("Expression cannot be implemented with read/access watchpoint."));
if (mem_cnt != 0)
{
+ struct type *vtype = check_typedef (value_type (val));
+
+ /* If we are going to use masks, then we may need more
+ slots in order to use the hardware watchpoint. */
+ if (use_mask)
+ mem_cnt += target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+ /* If we are watching an array or struct, we may be able to do it using
+ a ranged watchpoint. */
+ else if ((TYPE_CODE (vtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (vtype) == TYPE_CODE_ARRAY)
+ && target_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+ {
+ use_ranged = 1;
+ mem_cnt += target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+ }
+
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
target_can_use_hardware_watchpoint (bp_type, i + mem_cnt,
@@ -8201,10 +8620,22 @@ watch_command_1 (char *arg, int accessfl
error (_("Target can only support one kind of HW watchpoint at a time."));
}

- /* Change the type of breakpoint to an ordinary watchpoint if a hardware
- watchpoint could not be set. */
if (!mem_cnt || target_resources_ok <= 0)
- bp_type = bp_watchpoint;
+ {
+ if (use_mask && !mem_cnt)
+ error (_("Cannot use masks with the given expression."));
+ else if (use_mask && target_resources_ok <= 0)
+ error (_("\
+Cannot use masks without enough available hardware watchpoints (need %d)."),
+ mem_cnt);
+ else
+ {
+ /* Change the type of breakpoint to an ordinary watchpoint if a
+ hardware watchpoint could not be set. */
+ bp_type = bp_watchpoint;
+ use_ranged = 0;
+ }
+ }

frame = block_innermost_frame (exp_valid_block);

@@ -8273,7 +8704,16 @@ watch_command_1 (char *arg, int accessfl
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
b->val_valid = 1;
- b->ops = &watchpoint_breakpoint_ops;
+
+ if (use_mask)
+ {
+ b->hw_wp_mask = hw_wp_mask;
+ b->ops = &masked_watchpoint_breakpoint_ops;
+ }
+ else if (use_ranged)
+ b->ops = &ranged_watchpoint_breakpoint_ops;
+ else
+ b->ops = &watchpoint_breakpoint_ops;

if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -8458,6 +8898,92 @@ awatch_command (char *arg, int from_tty)
{
watch_maybe_just_location (arg, hw_access, from_tty);
}
+
+static void
+watch_range_command_1 (char *arg, enum bptype type, int from_tty)
+{
+ char *exp_string, *string_p;
+ struct gdbarch *gdbarch = get_current_arch ();
+ int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0;
+ CORE_ADDR start_addr;
+ ULONGEST length;
+ struct breakpoint *b;
+ struct expression *exp;
+ struct symtab_and_line sal;
+ struct value *val;
+ struct cleanup *cleanups;
+
+ /* Do we support ranged hardware watchpoints? */
+ if (!target_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+ error (_("This target does not support ranged hardware watchpoints."));
+ /* Did the user specifically forbid us to use hardware watchpoints? */
+ else if (!can_use_hw_watchpoints)
+ error (_("\
+Hardware watchpoints are disabled (see \"set can-use-hw-watchpoints\")."));
+
+ parse_addr_range (&arg, &start_addr, &length);
+
+ /* We need spaces around the brackets in the expression below so that
+ print_it_recreate_ranged_watchpoint can use scanf on it. */
+ exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length),
+ paddress (gdbarch, start_addr));
+ exp = parse_exp_1 (&string_p, 0, 0);
+ fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+ if (val != NULL)
+ release_value (val);
+ cleanups = make_cleanup (xfree, exp_string);
+
+ mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1;
+
+ wp_count = hw_watchpoint_used_count (type, &other_type_used);
+ can_use_wp = target_can_use_hardware_watchpoint (type, wp_count + mem_cnt,
+ other_type_used);
+ if (can_use_wp < 0)
+ error (_("Not enough available hardware watchpoints (need %d)."), mem_cnt);
+
+ init_sal (&sal); /* initialize to zeroes */
+ sal.pspace = current_program_space;
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (gdbarch, sal, type);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->thread = -1;
+ b->disposition = disp_donttouch;
+ b->exp = exp;
+ b->exp_string_reparse = exp_string;
+ b->exp_string = xstrprintf (_("range [%s, %s]"),
+ paddress (gdbarch, start_addr),
+ paddress (gdbarch, start_addr + length - 1));
+ b->ops = &ranged_watchpoint_breakpoint_ops;
+ b->val = val;
+ b->val_valid = 1;
+ b->watchpoint_frame = null_frame_id;
+
+ mention (b);
+ update_global_location_list (1);
+
+ discard_cleanups (cleanups);
+}
+
+static void
+watch_range_command (char *arg, int from_tty)
+{
+ watch_range_command_1 (arg, bp_hardware_watchpoint, from_tty);
+}
+
+static void
+awatch_range_command (char *arg, int from_tty)
+{
+ watch_range_command_1 (arg, bp_access_watchpoint, from_tty);
+}
+
+static void
+rwatch_range_command (char *arg, int from_tty)
+{
+ watch_range_command_1 (arg, bp_read_watchpoint, from_tty);
+}
+
\f

/* Helper routines for the until_command routine in infcmd.c. Here
@@ -8695,7 +9221,7 @@ catch_exec_command_1 (char *arg, int fro
}

static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_exception_catchpoint (struct breakpoint *b, const struct value *old_val)
{
int bp_temp, bp_throw;

@@ -8784,8 +9310,10 @@ static struct breakpoint_ops gnu_v3_exce
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
+ NULL, /* extra_resources_needed */
print_exception_catchpoint,
print_one_exception_catchpoint,
+ NULL, /* print_one_detail */
print_mention_exception_catchpoint,
print_recreate_exception_catchpoint
};
@@ -12159,7 +12687,41 @@ inferior in all-stop mode, gdb behaves a
&show_always_inserted_mode,
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
-
+
+ c = add_com ("watch-range", class_breakpoint, watch_range_command, _("\
+Set a hardware watchpoint for an address range.\n\
+The address range should be specified in one of the following formats:\n\
+\n\
+ start-address, end-address\n\
+ start-address, +length\n\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+writes to any address within the [start-address, end-address] interval."));
+ set_cmd_completer (c, expression_completer);
+
+ c = add_com ("awatch-range", class_breakpoint, awatch_range_command, _("\
+Set an access hardware watchpoint for an address range.\n\
+The address range should be specified in one of the following formats:\n\
+\n\
+ start-address, end-address\n\
+ start-address, +length\n\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+accesses (reads from or writes to) any address within the\n\
+[start-address, end-address] interval."));
+ set_cmd_completer (c, expression_completer);
+
+ c = add_com ("rwatch-range", class_breakpoint, rwatch_range_command, _("\
+Set a read hardware watchpoint for an address range.\n\
+The address range should be specified in one of the following formats:\n\
+\n\
+ start-address, end-address\n\
+ start-address, +length\n\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+reads from any address within the [start-address, end-address] interval."));
+ set_cmd_completer (c, expression_completer);
+
automatic_hardware_breakpoints = 1;

observer_attach_about_to_proceed (breakpoint_about_to_proceed);
Index: gdb.git/gdb/breakpoint.h
===================================================================
--- gdb.git.orig/gdb/breakpoint.h 2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/breakpoint.h 2010-08-17 12:31:28.000000000 -0300
@@ -26,6 +26,7 @@

struct value;
struct block;
+struct ui_out;

/* This is the maximum number of bytes a breakpoint instruction can take.
Feel free to increase it. It's just used in a few places to size
@@ -356,13 +357,23 @@ struct breakpoint_ops
breakpoint was hit. */
int (*breakpoint_hit) (struct breakpoint *);

+ /* Tell how many additional hardware resources (debug registers) are needed
+ for this breakpoint. We always count at least one resource. If this
+ element is NULL, then no additional resource is accounted for. */
+ int (*extra_resources_needed) (const struct breakpoint *);
+
/* The normal print routine for this breakpoint, called when we
hit it. */
- enum print_stop_action (*print_it) (struct breakpoint *);
+ enum print_stop_action (*print_it) (struct breakpoint *,
+ const struct value *old_val);

/* Display information about this breakpoint, for "info breakpoints". */
void (*print_one) (struct breakpoint *, struct bp_location **);

+ /* Display one line of extra information about this breakpoint,
+ for "info breakpoints". */
+ void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
/* Display information about this breakpoint after setting it (roughly
speaking; this is called from "mention"). */
void (*print_mention) (struct breakpoint *);
@@ -395,6 +406,12 @@ DEF_VEC_P(bp_location_p);
detail to the breakpoints module. */
struct counted_command_line;

+/* Special types of hardware breakpoints/watchpoints. */
+enum hw_point_flag {
+ HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint. */
+ HW_POINT_MASKED_WATCH /* Hardware masked watchpoint. */
+};
+
/* 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
@@ -559,6 +576,9 @@ struct breakpoint
breakpoints, we will use this index to try to find the same
marker again. */
int static_trace_marker_id_idx;
+
+ /* The mask address for a hardware watchpoint. */
+ CORE_ADDR hw_wp_mask;
};

typedef struct breakpoint *breakpoint_p;
Index: gdb.git/gdb/doc/gdb.texinfo
===================================================================
--- gdb.git.orig/gdb/doc/gdb.texinfo 2010-08-17 12:30:34.000000000 -0300
+++ gdb.git/gdb/doc/gdb.texinfo 2010-08-17 12:31:28.000000000 -0300
@@ -3711,7 +3711,7 @@ watchpoints, which do not slow down the

@table @code
@kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
Set a watchpoint for an expression. @value{GDBN} will break when the
expression @var{expr} is written into by the program and its value
changes. The simplest (and the most popular) use of this command is
@@ -3728,6 +3728,11 @@ change the value of @var{expr}, @value{G
that watchpoints restricted to a single thread in this way only work
with Hardware Watchpoints.

+The @code{@r{[}mask @var{maskvalue}@r{]}} clause is used to create a masked
+watchpoint if the current architecture supports the feature (currently,
+only available in the PowerPC Embedded architecture.
+See @ref{PowerPC Embedded}).
+
Ordinarily a watchpoint respects the scope of variables in @var{expr}
(see below). The @code{-location} argument tells @value{GDBN} to
instead watch the memory referred to by @var{expr}. In this case,
@@ -3738,12 +3743,12 @@ result does not have an address, then @v
error.

@kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
Set a watchpoint that will break when the value of @var{expr} is read
by the program.

@kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
Set a watchpoint that will break when @var{expr} is either read from
or written into by the program.

@@ -18483,9 +18488,41 @@ The DVC register will be automatically u
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.

+PowerPC embedded processors support additional types of hardware watchpoints,
+namely masked watchpoints and ranged watchpoints.
+
+A @dfn{masked watchpoint} is defined by an address and a mask. It triggers
+when the address of a memory access matches the watchpoint address when both
+are masked by the watchpoint mask. That is, the bits set in the mask determine
+which bits are relevant in the address comparison. To set a masked watchpoint
+in @value{GDBN}, use the @code{mask} parameter in the @code{watch} command
+(see @ref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
+A @dfn{ranged watchpoint} is defined by a start address and an end address
+specifying a region of memory inside which any access will trigger the
+watchpoint. Both the start and end addresses are within the memory region.
+To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command.
+
@value{GDBN} provides the following PowerPC-specific commands:

@table @code
+@kindex watch-range
+@item watch-range @var{start-address, +length}
+@itemx watch-range @var{start-address, end-address}
+@item rwatch-range @var{start-address, +length}
+@itemx rwatch-range @var{start-address, end-address}
+@item awatch-range @var{start-address, +length}
+@itemx awatch-range @var{start-address, end-address}
+Set a hardware watchpoint for an address range.
+The watchpoint will stop execution of your program whenever the inferior
+writes, reads, or accesses (respectively for watch-range, awatch-range
+and rwatch-range) any address within the @code{[start-address, end-address]}
+interval.
+
@kindex set powerpc
@item set powerpc soft-float
@itemx show powerpc soft-float
Index: gdb.git/gdb/findcmd.c
===================================================================
--- gdb.git.orig/gdb/findcmd.c 2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/findcmd.c 2010-08-17 12:31:28.000000000 -0300
@@ -45,6 +45,79 @@ put_bits (bfd_uint64_t data, char *buf,
}
}

+/* Reads an address range, in one of the following formats:
+
+ start-address, end-address
+ start-address, +length
+
+ ARGS will be set to the first character after the end-address or length,
+ or if that character is a comma, the character following it. If a parser
+ error occurs, an exception is thrown and none of the arguments is
+ touched. Returns 1 on success, or 0 if an empty address range was given. */
+
+int
+parse_addr_range (char **args, CORE_ADDR *start_addrp,
+ ULONGEST *search_space_lenp)
+{
+ char *s = *args;
+ CORE_ADDR start_addr;
+ ULONGEST search_space_len;
+ struct value *v;
+
+ v = parse_to_comma_and_eval (&s);
+ start_addr = value_as_address (v);
+
+ if (*s == ',')
+ ++s;
+ while (isspace (*s))
+ ++s;
+
+ if (*s == '+')
+ {
+ LONGEST len;
+
+ ++s;
+ v = parse_to_comma_and_eval (&s);
+ len = value_as_long (v);
+ if (len == 0)
+ {
+ printf_filtered (_("Empty search range.\n"));
+ return 0;
+ }
+ if (len < 0)
+ error (_("Invalid length."));
+ /* Watch for overflows. */
+ if (len > CORE_ADDR_MAX
+ || (start_addr + len - 1) < start_addr)
+ error (_("Search space too large."));
+ search_space_len = len;
+ }
+ else
+ {
+ CORE_ADDR end_addr;
+
+ v = parse_to_comma_and_eval (&s);
+ end_addr = value_as_address (v);
+ if (start_addr > end_addr)
+ error (_("Invalid search space, end preceeds start."));
+ search_space_len = end_addr - start_addr + 1;
+ /* We don't support searching all of memory
+ (i.e. start=0, end = 0xff..ff).
+ Bail to avoid overflows later on. */
+ if (search_space_len == 0)
+ error (_("Overflow in address range computation, choose smaller range."));
+ }
+
+ if (*s == ',')
+ ++s;
+
+ *args = s;
+ *start_addrp = start_addr;
+ *search_space_lenp = search_space_len;
+
+ return 1;
+}
+
/* Subroutine of find_command to simplify it.
Parse the arguments of the "find" command. */

@@ -114,53 +187,8 @@ parse_find_args (char *args, ULONGEST *m
}

/* Get the search range. */
-
- v = parse_to_comma_and_eval (&s);
- start_addr = value_as_address (v);
-
- if (*s == ',')
- ++s;
- while (isspace (*s))
- ++s;
-
- if (*s == '+')
- {
- LONGEST len;
-
- ++s;
- v = parse_to_comma_and_eval (&s);
- len = value_as_long (v);
- if (len == 0)
- {
- printf_filtered (_("Empty search range.\n"));
- return;
- }
- if (len < 0)
- error (_("Invalid length."));
- /* Watch for overflows. */
- if (len > CORE_ADDR_MAX
- || (start_addr + len - 1) < start_addr)
- error (_("Search space too large."));
- search_space_len = len;
- }
- else
- {
- CORE_ADDR end_addr;
-
- v = parse_to_comma_and_eval (&s);
- end_addr = value_as_address (v);
- if (start_addr > end_addr)
- error (_("Invalid search space, end preceeds start."));
- search_space_len = end_addr - start_addr + 1;
- /* We don't support searching all of memory
- (i.e. start=0, end = 0xff..ff).
- Bail to avoid overflows later on. */
- if (search_space_len == 0)
- error (_("Overflow in address range computation, choose smaller range."));
- }
-
- if (*s == ',')
- ++s;
+ if (!parse_addr_range (&s, &start_addr, &search_space_len))
+ return;

/* Fetch the search string. */

Index: gdb.git/gdb/ppc-linux-nat.c
===================================================================
--- gdb.git.orig/gdb/ppc-linux-nat.c 2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ppc-linux-nat.c 2010-08-17 12:31:28.000000000 -0300
@@ -1478,6 +1478,28 @@ ppc_linux_can_use_hw_breakpoint (int typ
}

static int
+ppc_linux_can_use_special_hw_point (enum hw_point_flag flag)
+{
+ uint64_t features;
+
+ if (!have_ptrace_booke_interface ())
+ return 0;
+
+ features = booke_debug_info.features;
+
+ switch (flag)
+ {
+ case HW_POINT_RANGED_WATCH:
+ return features & PPC_DEBUG_FEATURE_DATA_BP_RANGE;
+ case HW_POINT_MASKED_WATCH:
+ return features & PPC_DEBUG_FEATURE_DATA_BP_MASK;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Unknown hardware breakpoint/watchpoint type."));
+ }
+}
+
+static int
ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
/* Handle sub-8-byte quantities. */
@@ -1489,9 +1511,15 @@ ppc_linux_region_ok_for_hw_watchpoint (C
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 (ppc_linux_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+ return 1;
+ 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
@@ -1685,6 +1713,106 @@ get_trigger_type (int rw)
return t;
}

+static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+ ptid_t ptid;
+ struct lwp_info *lp;
+ struct ppc_hw_breakpoint p;
+
+ gdb_assert (have_ptrace_booke_interface ());
+
+ if ((mask & 0xC0000000) != 0xC0000000)
+ error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.addr = (uint64_t) addr;
+ p.addr2 = (uint64_t) mask;
+ p.condition_value = 0;
+
+ ALL_LWPS (lp, ptid)
+ booke_insert_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
+ppc_linux_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+ ptid_t ptid;
+ struct lwp_info *lp;
+ struct ppc_hw_breakpoint p;
+
+ gdb_assert (have_ptrace_booke_interface ());
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.addr = (uint64_t) addr;
+ p.addr2 = (uint64_t) mask;
+ p.condition_value = 0;
+
+ ALL_LWPS (lp, ptid)
+ booke_remove_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+ ptid_t ptid;
+ struct lwp_info *lp;
+ struct ppc_hw_breakpoint p;
+
+ gdb_assert (have_ptrace_booke_interface ());
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ 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. */
+ p.addr = (uint64_t) addr;
+ p.addr2 = (uint64_t) addr + len;
+
+ ALL_LWPS (lp, ptid)
+ booke_insert_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
+ppc_linux_remove_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+ ptid_t ptid;
+ struct lwp_info *lp;
+ struct ppc_hw_breakpoint p;
+
+ gdb_assert (have_ptrace_booke_interface ());
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = get_trigger_type (rw);
+ p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.addr = (uint64_t) addr;
+ p.addr2 = (uint64_t) addr + len;
+ p.condition_value = 0;
+
+ ALL_LWPS (lp, ptid)
+ booke_remove_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
/* Check whether we have at least one free DVC register. */
static int
can_use_watchpoint_cond_accel (void)
@@ -2136,6 +2264,14 @@ ppc_linux_watchpoint_addr_within_range (
return start <= addr + mask && start + length - 1 >= addr;
}

+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+ gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH);
+
+ return 1;
+}
+
static void
ppc_linux_store_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
@@ -2347,12 +2483,18 @@ _initialize_ppc_linux_nat (void)
t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+ t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point;
t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+ t->to_insert_ranged_watchpoint = ppc_linux_insert_ranged_watchpoint;
+ t->to_remove_ranged_watchpoint = ppc_linux_remove_ranged_watchpoint;
+ t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+ t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
t->to_stopped_data_address = ppc_linux_stopped_data_address;
t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+ t->to_hw_point_extra_slot_count = ppc_linux_hw_point_extra_slot_count;

t->to_read_description = ppc_linux_read_description;
t->to_auxv_parse = ppc_linux_auxv_parse;
Index: gdb.git/gdb/target.c
===================================================================
--- gdb.git.orig/gdb/target.c 2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/target.c 2010-08-17 12:31:28.000000000 -0300
@@ -601,11 +601,16 @@ update_current_target (void)
INHERIT (to_files_info, t);
INHERIT (to_insert_breakpoint, t);
INHERIT (to_remove_breakpoint, t);
+ INHERIT (to_can_use_special_hw_point, t);
INHERIT (to_can_use_hw_breakpoint, t);
INHERIT (to_insert_hw_breakpoint, t);
INHERIT (to_remove_hw_breakpoint, t);
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
+ INHERIT (to_insert_ranged_watchpoint, t);
+ INHERIT (to_remove_ranged_watchpoint, t);
+ INHERIT (to_insert_mask_watchpoint, t);
+ INHERIT (to_remove_mask_watchpoint, t);
INHERIT (to_stopped_data_address, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +618,7 @@ update_current_target (void)
INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
INHERIT (to_can_accel_watchpoint_condition, t);
+ INHERIT (to_hw_point_extra_slot_count, t);
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
INHERIT (to_terminal_ours_for_output, t);
@@ -727,6 +733,9 @@ update_current_target (void)
de_fault (to_can_use_hw_breakpoint,
(int (*) (int, int, int))
return_zero);
+ de_fault (to_can_use_special_hw_point,
+ (int (*) (enum hw_point_flag))
+ return_zero);
de_fault (to_insert_hw_breakpoint,
(int (*) (struct gdbarch *, struct bp_target_info *))
return_minus_one);
@@ -739,6 +748,18 @@ update_current_target (void)
de_fault (to_remove_watchpoint,
(int (*) (CORE_ADDR, int, int, struct expression *))
return_minus_one);
+ de_fault (to_insert_ranged_watchpoint,
+ (int (*) (CORE_ADDR, int, int))
+ return_minus_one);
+ de_fault (to_remove_ranged_watchpoint,
+ (int (*) (CORE_ADDR, int, int))
+ return_minus_one);
+ de_fault (to_insert_mask_watchpoint,
+ (int (*) (CORE_ADDR, CORE_ADDR, int))
+ return_minus_one);
+ de_fault (to_remove_mask_watchpoint,
+ (int (*) (CORE_ADDR, CORE_ADDR, int))
+ return_minus_one);
de_fault (to_stopped_by_watchpoint,
(int (*) (void))
return_zero);
@@ -752,6 +773,9 @@ update_current_target (void)
de_fault (to_can_accel_watchpoint_condition,
(int (*) (CORE_ADDR, int, int, struct expression *))
return_zero);
+ de_fault (to_hw_point_extra_slot_count,
+ (int (*) (enum hw_point_flag))
+ return_zero);
de_fault (to_terminal_init,
(void (*) (void))
target_ignore);
Index: gdb.git/gdb/target.h
===================================================================
--- gdb.git.orig/gdb/target.h 2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/target.h 2010-08-17 12:31:28.000000000 -0300
@@ -39,6 +39,8 @@ struct static_tracepoint_marker;

struct expression;

+enum hw_point_flag;
+
/* This include file defines the interface between the main part
of the debugger, and the part which is target-specific, or
specific to the communications interface between us and the
@@ -438,6 +440,7 @@ struct target_ops
int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_can_use_hw_breakpoint) (int, int, int);
+ int (*to_can_use_special_hw_point) (enum hw_point_flag);
int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);

@@ -446,6 +449,10 @@ struct target_ops
int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);

+ int (*to_insert_ranged_watchpoint) (CORE_ADDR, int, int);
+ int (*to_remove_ranged_watchpoint) (CORE_ADDR, int, int);
+ int (*to_insert_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int);
+ int (*to_remove_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int);
int (*to_stopped_by_watchpoint) (void);
int to_have_steppable_watchpoint;
int to_have_continuable_watchpoint;
@@ -455,6 +462,7 @@ struct target_ops
int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
struct expression *);
+ int (*to_hw_point_extra_slot_count) (enum hw_point_flag);
void (*to_terminal_init) (void);
void (*to_terminal_inferior) (void);
void (*to_terminal_ours_for_output) (void);
@@ -1318,6 +1326,11 @@ extern char *normal_pid_to_str (ptid_t p
#define target_region_ok_for_hw_watchpoint(addr, len) \
(*current_target.to_region_ok_for_hw_watchpoint) (addr, len)

+/* Returns non-zero if the target supports the special type of hardware
+ breakpoint/watchpoint represented by FLAG. */
+#define target_can_use_special_hw_point(flag) \
+ (*current_target.to_can_use_special_hw_point) (flag)
+

/* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
@@ -1331,6 +1344,20 @@ extern char *normal_pid_to_str (ptid_t p
#define target_remove_watchpoint(addr, len, type, cond) \
(*current_target.to_remove_watchpoint) (addr, len, type, cond)

+/* Hardware ranged watchpoints. */
+#define target_insert_ranged_watchpoint(addr, len, type) \
+ (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+
+#define target_remove_ranged_watchpoint(addr, len, type) \
+ (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+
+/* Hardware watchpoints with an associated address mask. */
+#define target_insert_mask_watchpoint(addr, mask, type) \
+ (*current_target.to_insert_mask_watchpoint) (addr, mask, type)
+
+#define target_remove_mask_watchpoint(addr, mask, type) \
+ (*current_target.to_remove_mask_watchpoint) (addr, mask, type)
+
#define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
(*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)

@@ -1359,6 +1386,9 @@ extern char *normal_pid_to_str (ptid_t p
#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
(*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)

+#define target_hw_point_extra_slot_count(flag) \
+ (*current_target.to_hw_point_extra_slot_count) (flag)
+
/* Target can execute in reverse? */
#define target_can_execute_reverse \
(current_target.to_can_execute_reverse ? \
Index: gdb.git/gdb/ui-out.c
===================================================================
--- gdb.git.orig/gdb/ui-out.c 2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ui-out.c 2010-08-17 12:31:28.000000000 -0300
@@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uio
}

void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+ const char *fldname,
+ struct gdbarch *gdbarch,
+ CORE_ADDR address_start,
+ CORE_ADDR length)
+{
+ char addstr[80];
+ int addr_bit = gdbarch_addr_bit (gdbarch);
+ CORE_ADDR address_end = address_start + length - 1;
+
+ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+ {
+ address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+ address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+ }
+
+ /* FIXME: cagney/2002-05-03: Need local_address_string() function
+ that returns the language localized string formatted to a width
+ based on gdbarch_addr_bit. */
+ if (addr_bit <= 32)
+ {
+ strcpy (addstr, "[");
+ strcat (addstr, hex_string_custom (address_start, 8));
+ strcat (addstr, ", ");
+ strcat (addstr, hex_string_custom (address_end, 8));
+ strcat (addstr, "]");
+ }
+ else
+ {
+ strcpy (addstr, "[");
+ strcat (addstr, hex_string_custom (address_start, 16));
+ strcat (addstr, ", ");
+ strcat (addstr, hex_string_custom (address_end, 16));
+ strcat (addstr, "]");
+ }
+
+ ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
ui_out_field_core_addr (struct ui_out *uiout,
const char *fldname,
struct gdbarch *gdbarch,
Index: gdb.git/gdb/ui-out.h
===================================================================
--- gdb.git.orig/gdb/ui-out.h 2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ui-out.h 2010-08-17 12:31:28.000000000 -0300
@@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct
enum ui_align align, const char *fldname,
int value);

+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+ const char *fldname,
+ struct gdbarch *gdbarch,
+ CORE_ADDR address_start,
+ CORE_ADDR length);
+
extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
struct gdbarch *gdbarch, CORE_ADDR address);

Index: gdb.git/gdb/value.h
===================================================================
--- gdb.git.orig/gdb/value.h 2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/value.h 2010-08-17 12:31:28.000000000 -0300
@@ -559,6 +559,9 @@ extern CORE_ADDR parse_and_eval_address_

extern LONGEST parse_and_eval_long (char *exp);

+int parse_addr_range (char **args, CORE_ADDR *start_addrp,
+ ULONGEST *search_space_lenp);
+
extern void unop_promote (const struct language_defn *language,
struct gdbarch *gdbarch,
struct value **arg1);