[RFA] Implement support for PowerPC BookE ranged breakpoints

Thiago Jung Bauermann
2011-01-28T01:27:05Z

Hi all,

This is (finally!) the last patch in my series to support BookE hardware
debug features. It adds the following command:

(gdb) help break-range
Set a breakpoint for an address range.
break-range START-LOCATION, END-LOCATION
where START-LOCATION and END-LOCATION can be one of the following:
LINENUM, for that line in the current file,
FILE:LINENUM, for that line in that file,
+OFFSET, for that number of lines after the current line
or the start of the range
FUNCTION, for the first line in that function,
FILE:FUNCTION, to distinguish among like-named static functions.
*ADDRESS, for the instruction at that address.

The breakpoint will stop execution of the inferior whenever it
executes any address within the [start-address, end-address] range
(including START-LOCATION and END-LOCATION).

This patch needs a doc review.

There are no regressions on ppc-linux, ppc64-linux and i386-linux. Ok?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

2011-01-27 Thiago Jung Bauermann <bauerman@br.ibm.com>
Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>

Implement support for PowerPC BookE ranged breakpoints.

gdb/
* NEWS: Mention support for ranged breakpoints on embedded
PowerPC.
* breakpoint.h (struct ui_stream): Add opaque declaration.
(struct bp_target_info) <length>: New member variable.
(struct breakpoint_ops) <breakpoint_hit>: Take struct bp_location
instead of struct breakpoint as argument, and also add ASPACE
and BP_ADDR arguments. Update all callers.
(struct breakpoint_ops) <print_it>: Take struct bp_location
instead of struct breakpoint as argument. Update all callers.
(struct breakpoint_ops) <print_one>: Add WRAP_INDENT and STB
arguments. Update all callers.
(struct breakpoint_ops) <print_mention>: Add SAY_WHERE argument.
Update all callers.
* breakpoint.c (breakpoint_address_match_range): Add function
prototype.
(is_ranged_breakpoint): Likewise.
(insert_bp_location): Set bl->target_info.length.
(breakpoint_here_p): Check for address match for in ranged
breakpoints.
(print_it_typical): Move NULL check from here...
(print_bp_stop_message): ... to here.
(bpstat_check_location): Move call to
breakpoint_ops.breakpoint_hit to the top.
(breakpoint_address_match_range): New function.
(hw_breakpoint_used_count): Count resources used by all locations
in a breakpoint, and use breakpoint_ops.resources_needed if
available.
(breakpoint_hit_ranged_breakpoint): New function.
(resources_needed_ranged_breakpoint): Likewise.
(print_it_ranged_breakpoint): Likewise.
(print_one_ranged_breakpoint): Likewise.
(print_one_detail_ranged_breakpoint): Likewise.
(print_mention_ranged_breakpoint): Likewise.
(print_recreate_ranged_breakpoint): Likewise.
(ranged_breakpoint_ops): New structure.
(is_ranged_breakpoint): New function.
(break_range_command): Likewise.
(_initialize_breakpoint): Register break-range command.
* ppc-linux-nat.c (ppc_linux_ranged_break_num_registers): New
function.
(ppc_linux_insert_hw_breakpoint): Support ranged breakpoints.
(ppc_linux_remove_hw_breakpoint): Likewise.
(_initialize_ppc_linux_nat): Initialize
to_ranged_break_num_registers.
* target.c (update_current_target): Add comment about
to_ranged_break_num_registers.
(target_ranged_break_num_registers): New function.
* target.h (struct target_ops) <to_ranged_break_num_registers>:
New method.
(target_ranged_break_num_registers): Add function prototype.
* ui-out.c (ui_out_field_range_core_addr): New function.
(ui_out_field_range_core_addr): Add function prototype.

gdb/doc/
* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.

diff --git a/gdb/NEWS b/gdb/NEWS
index d5d15ec..0a5d82d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -131,6 +131,12 @@
by the inferior against the watchpoint address. See the "PowerPC Embedded"
section in the user manual for more details.

+* When locally debugging programs on PowerPC BookE processors running
+ a Linux kernel version 2.6.34 or later, GDB supports ranged breakpoints,
+ which stop execution of the inferior whenever it executes any address
+ within the specified range. See the "PowerPC Embedded" section in the
+ user manual for more details.
+
* New features in the GDB remote stub, GDBserver

** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 2fda77f..7eedc0a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10875,20 +10875,23 @@ print_recreate_exception (enum exception_catchpoint_kind ex,
/* Virtual table for "catch exception" breakpoints. */

static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
+print_it_catch_exception (const struct bp_location *bl,
+ const struct value *old_val)
{
- return print_it_exception (ex_catch_exception, b);
+ return print_it_exception (ex_catch_exception, bl->owner);
}

static void
-print_one_catch_exception (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_exception (struct breakpoint *b, struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
print_one_exception (ex_catch_exception, b, last_loc);
}

static void
-print_mention_catch_exception (struct breakpoint *b)
+print_mention_catch_exception (struct breakpoint *b, int *say_where)
{
+ *say_where = 0;
print_mention_exception (ex_catch_exception, b);
}

@@ -10915,22 +10918,24 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
/* 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 (const struct bp_location *bl,
const struct value *old_val)
{
- return print_it_exception (ex_catch_exception_unhandled, b);
+ return print_it_exception (ex_catch_exception_unhandled, bl->owner);
}

static void
print_one_catch_exception_unhandled (struct breakpoint *b,
- struct bp_location **last_loc)
+ struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
print_one_exception (ex_catch_exception_unhandled, b, last_loc);
}

static void
-print_mention_catch_exception_unhandled (struct breakpoint *b)
+print_mention_catch_exception_unhandled (struct breakpoint *b, int *say_where)
{
+ *say_where = 0;
print_mention_exception (ex_catch_exception_unhandled, b);
}

@@ -10957,20 +10962,23 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
/* Virtual table for "catch assert" breakpoints. */

static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
+print_it_catch_assert (const struct bp_location *bl,
+ const struct value *old_val)
{
- return print_it_exception (ex_catch_assert, b);
+ return print_it_exception (ex_catch_assert, bl->owner);
}

static void
-print_one_catch_assert (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_assert (struct breakpoint *b, struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
print_one_exception (ex_catch_assert, b, last_loc);
}

static void
-print_mention_catch_assert (struct breakpoint *b)
+print_mention_catch_assert (struct breakpoint *b, int *say_where)
{
+ *say_where = 0;
print_mention_exception (ex_catch_assert, b);
}

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 7eef1b4..b939b6f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -128,6 +128,11 @@ static int breakpoint_address_match (struct address_space *aspace1,
static int watchpoint_locations_match (struct bp_location *loc1,
struct bp_location *loc2);

+static int breakpoint_address_match_range (struct address_space *aspace1,
+ CORE_ADDR addr1, CORE_ADDR len1,
+ struct address_space *aspace2,
+ CORE_ADDR addr2);
+
static void breakpoints_info (char *, int);

static void watchpoints_info (char *, int);
@@ -222,6 +227,8 @@ static void trace_pass_command (char *, int);

static int is_masked_watchpoint (const struct breakpoint *b);

+static int is_ranged_breakpoint (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) \
@@ -1644,6 +1651,7 @@ insert_bp_location (struct bp_location *bl,
memset (&bl->target_info, 0, sizeof (bl->target_info));
bl->target_info.placed_address = bl->address;
bl->target_info.placed_address_space = bl->pspace->aspace;
+ bl->target_info.length = bl->length;

if (bl->loc_type == bp_loc_software_breakpoint
|| bl->loc_type == bp_loc_hardware_breakpoint)
@@ -2771,11 +2779,15 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
&& bl->loc_type != bp_loc_hardware_breakpoint)
continue;

- /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL. */
+ /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL. */
if ((breakpoint_enabled (bl->owner)
|| bl->owner->enable_state == bp_permanent)
- && breakpoint_address_match (bl->pspace->aspace, bl->address,
- aspace, pc))
+ && (breakpoint_address_match (bl->pspace->aspace, bl->address,
+ aspace, pc)
+ || (is_ranged_breakpoint (bl->owner)
+ && breakpoint_address_match_range (bl->pspace->aspace,
+ bl->address, bl->length,
+ aspace, pc))))
{
if (overlay_debugging
&& section_is_overlay (bl->section)
@@ -3306,11 +3318,6 @@ print_it_typical (bpstat bs)
int bp_temp = 0;
enum print_stop_action result;

- /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
- which has since been deleted. */
- if (bs->breakpoint_at == NULL)
- return PRINT_UNKNOWN;
-
gdb_assert (bs->bp_location_at != NULL);

bl = bs->bp_location_at;
@@ -3516,11 +3523,15 @@ print_bp_stop_message (bpstat bs)
{
struct breakpoint *b = bs->breakpoint_at;

+ /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+ which has since been deleted. */
+ if (b == NULL)
+ return PRINT_UNKNOWN;
+
/* Normal case. Call the breakpoint's print_it method, or
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, bs->old_val);
+ if (b->ops != NULL && b->ops->print_it != NULL)
+ return b->ops->print_it (bs->bp_location_at, bs->old_val);
else
return print_it_typical (bs);
}
@@ -3855,6 +3866,9 @@ bpstat_check_location (const struct bp_location *bl,
/* BL is from existing struct breakpoint. */
gdb_assert (b != NULL);

+ if (b->ops && b->ops->breakpoint_hit)
+ return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+
/* By definition, the inferior does not report stops at
tracepoints. */
if (is_tracepoint (b))
@@ -3883,7 +3897,7 @@ bpstat_check_location (const struct bp_location *bl,
if (is_hardware_watchpoint (b)
&& b->watchpoint_triggered == watch_triggered_no)
return 0;
-
+
if (b->type == bp_hardware_breakpoint)
{
if (bl->address != bp_addr)
@@ -3894,13 +3908,6 @@ bpstat_check_location (const struct bp_location *bl,
return 0;
}

- if (b->type == bp_catchpoint)
- {
- gdb_assert (b->ops != NULL && b->ops->breakpoint_hit != NULL);
- if (!b->ops->breakpoint_hit (b))
- return 0;
- }
-
return 1;
}

@@ -4775,7 +4782,7 @@ print_one_breakpoint_location (struct breakpoint *b,
calling it here is not likely to get any nice result. So,
make sure there's just one location. */
gdb_assert (b->loc == NULL || b->loc->next == NULL);
- b->ops->print_one (b, last_loc);
+ b->ops->print_one (b, last_loc, wrap_indent, stb);
}
else
switch (b->type)
@@ -5467,6 +5474,21 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
&& addr1 == addr2);
}

+/* Returns true if {ASPACE2,ADDR2} falls within the range determined by
+ {ASPACE1,ADDR1,LEN1}. In most targets, this can only be true if ASPACE1
+ matches ASPACE2. On targets that have global breakpoints, the address
+ space doesn't really matter. */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+ CORE_ADDR len1, struct address_space *aspace2,
+ CORE_ADDR addr2)
+{
+ return ((gdbarch_has_global_breakpoints (target_gdbarch)
+ || aspace1 == aspace2)
+ && addr2 >= addr1 && addr2 < addr1 + len1);
+}
+
/* Assuming LOC1 and LOC2's types' have meaningful target addresses
(breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
represent the same location. */
@@ -6084,17 +6106,20 @@ remove_catch_fork (struct bp_location *bl)
catchpoints. */

static int
-breakpoint_hit_catch_fork (struct breakpoint *b)
+breakpoint_hit_catch_fork (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
- return inferior_has_forked (inferior_ptid, &b->forked_inferior_pid);
+ return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
}

/* Implement the "print_it" breakpoint_ops method for fork
catchpoints. */

static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
+print_it_catch_fork (const struct bp_location *bl, const struct value *old_val)
{
+ const struct breakpoint *b = bl->owner;
+
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (forked process %d), "),
b->number, ptid_get_pid (b->forked_inferior_pid));
@@ -6105,7 +6130,8 @@ print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
catchpoints. */

static void
-print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
struct value_print_options opts;

@@ -6131,8 +6157,9 @@ print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
catchpoints. */

static void
-print_mention_catch_fork (struct breakpoint *b)
+print_mention_catch_fork (struct breakpoint *b, int *say_where)
{
+ *say_where = 0;
printf_filtered (_("Catchpoint %d (fork)"), b->number);
}

@@ -6183,17 +6210,20 @@ remove_catch_vfork (struct bp_location *bl)
catchpoints. */

static int
-breakpoint_hit_catch_vfork (struct breakpoint *b)
+breakpoint_hit_catch_vfork (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
- return inferior_has_vforked (inferior_ptid, &b->forked_inferior_pid);
+ return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
}

/* Implement the "print_it" breakpoint_ops method for vfork
catchpoints. */

static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
+print_it_catch_vfork (const struct bp_location *bl, const struct value *old_val)
{
+ const struct breakpoint *b = bl->owner;
+
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
b->number, ptid_get_pid (b->forked_inferior_pid));
@@ -6204,7 +6234,8 @@ print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
catchpoints. */

static void
-print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
struct value_print_options opts;

@@ -6229,8 +6260,9 @@ print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
catchpoints. */

static void
-print_mention_catch_vfork (struct breakpoint *b)
+print_mention_catch_vfork (struct breakpoint *b, int *say_where)
{
+ *say_where = 0;
printf_filtered (_("Catchpoint %d (vfork)"), b->number);
}

@@ -6344,12 +6376,14 @@ remove_catch_syscall (struct bp_location *bl)
catchpoints. */

static int
-breakpoint_hit_catch_syscall (struct breakpoint *b)
+breakpoint_hit_catch_syscall (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
/* We must check if we are catching specific syscalls in this
breakpoint. If we are, then we must guarantee that the called
syscall is the same syscall we are catching. */
int syscall_number = 0;
+ const struct breakpoint *b = bl->owner;

if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
return 0;
@@ -6376,7 +6410,8 @@ breakpoint_hit_catch_syscall (struct breakpoint *b)
catchpoints. */

static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
+print_it_catch_syscall (const struct bp_location *bl,
+ 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
@@ -6387,6 +6422,7 @@ print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
struct syscall s;
struct cleanup *old_chain;
char *syscall_id;
+ const struct breakpoint *b = bl->owner;

get_last_target_status (&ptid, &last);

@@ -6417,8 +6453,8 @@ print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
catchpoints. */

static void
-print_one_catch_syscall (struct breakpoint *b,
- struct bp_location **last_loc)
+print_one_catch_syscall (struct breakpoint *b, struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
struct value_print_options opts;

@@ -6472,8 +6508,10 @@ print_one_catch_syscall (struct breakpoint *b,
catchpoints. */

static void
-print_mention_catch_syscall (struct breakpoint *b)
+print_mention_catch_syscall (struct breakpoint *b, int *say_where)
{
+ *say_where = 0;
+
if (b->syscalls_to_be_caught)
{
int i, iter;
@@ -6636,14 +6674,17 @@ remove_catch_exec (struct bp_location *bl)
}

static int
-breakpoint_hit_catch_exec (struct breakpoint *b)
+breakpoint_hit_catch_exec (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
- return inferior_has_execd (inferior_ptid, &b->exec_pathname);
+ return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
}

static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
+print_it_catch_exec (const struct bp_location *bl, const struct value *old_val)
{
+ const struct breakpoint *b = bl->owner;
+
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
b->exec_pathname);
@@ -6651,7 +6692,8 @@ print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
}

static void
-print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
+print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
struct value_print_options opts;

@@ -6673,8 +6715,9 @@ print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
}

static void
-print_mention_catch_exec (struct breakpoint *b)
+print_mention_catch_exec (struct breakpoint *b, int *say_where)
{
+ *say_where = 0;
printf_filtered (_("Catchpoint %d (exec)"), b->number);
}

@@ -6720,13 +6763,22 @@ create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
static int
hw_breakpoint_used_count (void)
{
- struct breakpoint *b;
int i = 0;
+ struct breakpoint *b;
+ struct bp_location *bl;

ALL_BREAKPOINTS (b)
{
if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
- i++;
+ for (bl = b->loc; bl; bl = bl->next)
+ {
+ /* Special types of hardware breakpoints may use more than
+ one register. */
+ if (b->ops && b->ops->resources_needed)
+ i += b->ops->resources_needed (bl);
+ else
+ i++;
+ }
}

return i;
@@ -6948,7 +7000,7 @@ mention (struct breakpoint *b)
observer_notify_breakpoint_created (b->number);

if (b->ops != NULL && b->ops->print_mention != NULL)
- b->ops->print_mention (b);
+ b->ops->print_mention (b, &say_where);
else
switch (b->type)
{
@@ -8192,6 +8244,329 @@ stopat_command (char *arg, int from_tty)
break_command_1 (arg, 0, from_tty);
}

+/* Implement the "breakpoint_hit" breakpoint_ops method for
+ ranged breakpoints. */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+ struct address_space *aspace,
+ CORE_ADDR bp_addr)
+{
+ return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+ bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+ ranged breakpoints. */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+ return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+ ranged breakpoints. */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (const struct bp_location *bl,
+ const struct value *old_val)
+{
+ const struct breakpoint *b = bl->owner;
+ struct ui_stream *stb;
+ struct cleanup *old_chain;
+
+ gdb_assert (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint);
+
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+ if (bl->address != bl->requested_address)
+ breakpoint_adjustment_warning (bl->requested_address,
+ bl->address,
+ b->number, 1);
+ annotate_breakpoint (b->number);
+ if (b->disposition == disp_del)
+ ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+ else if (b->type == bp_hardware_breakpoint)
+ ui_out_text (uiout, "\nHardware assisted ranged breakpoint ");
+ else
+ ui_out_text (uiout, "\nRanged breakpoint ");
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_string (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+ ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+ }
+ ui_out_field_int (uiout, "bkptno", b->number);
+ ui_out_text (uiout, ", ");
+
+ do_cleanups (old_chain);
+
+ return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+ ranged breakpoints. */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+ struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
+{
+ struct value_print_options opts;
+
+ /* We're prepared to deal with only one location. */
+ gdb_assert (b->loc && !b->loc->next);
+
+ get_user_print_options (&opts);
+
+ if (opts.addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ if (b->loc->enabled)
+ print_breakpoint_location (b, b->loc, wrap_indent, stb);
+ if (b->loc)
+ *last_loc = b->loc;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+ ranged breakpoints. */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+ struct ui_out *uiout)
+{
+ gdb_assert (b->loc);
+
+ ui_out_text (uiout, "\taddress 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 breakpoints. */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b, int *say_where)
+{
+ switch (b->type)
+ {
+ case bp_breakpoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ *say_where = 0;
+ break;
+ }
+ if (b->disposition == disp_del)
+ printf_filtered (_("Temporary ranged breakpoint"));
+ else
+ printf_filtered (_("Ranged breakpoint"));
+ printf_filtered (_(" %d"), b->number);
+ *say_where = 1;
+ break;
+ case bp_hardware_breakpoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ *say_where = 0;
+ break;
+ }
+
+ printf_filtered (_("Hardware assisted ranged breakpoint %d"), b->number);
+ *say_where = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("Invalid breakpoint type."));
+ }
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+ ranged breakpoints. */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
+{
+ fprintf_unfiltered (fp, "break-range %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints. */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+ NULL, /* insert */
+ NULL, /* remove */
+ breakpoint_hit_ranged_breakpoint,
+ resources_needed_ranged_breakpoint,
+ NULL, /* works_in_software_mode */
+ print_it_ranged_breakpoint,
+ print_one_ranged_breakpoint,
+ print_one_detail_ranged_breakpoint,
+ print_mention_ranged_breakpoint,
+ print_recreate_ranged_breakpoint
+};
+
+/* Tell whether the given breakpoint is a ranged breakpoint. */
+
+static int
+is_ranged_breakpoint (const struct breakpoint *b)
+{
+ return b->ops == &ranged_breakpoint_ops;
+}
+
+/* Implement the "break-range" CLI command. */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+ char *orig_arg;
+ char **addr_string_start;
+ int bp_count, can_use_bp, ret;
+ CORE_ADDR start_addr, start, end;
+ LONGEST length;
+ struct breakpoint *b;
+ struct symtabs_and_lines sals_start, sals_end;
+ struct gdbarch *gdbarch = get_current_arch ();
+ struct gdb_exception e;
+ struct cleanup *cleanup_start, *cleanup_end, *cleanup_orig_arg;
+
+ /* We don't support software ranged breakpoints. */
+ if (target_ranged_break_num_registers () < 0)
+ error (_("This target does not support hardware ranged breakpoints."));
+
+ bp_count = hw_breakpoint_used_count ();
+ bp_count += target_ranged_break_num_registers ();
+ can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+ bp_count, 0);
+ if (can_use_bp < 0)
+ error (_("Hardware breakpoints used exceeds limit."));
+
+ if (arg == NULL || arg[0] == '\0')
+ error(_("No address range specified."));
+
+ /* Save the original argument string for later use by
+ print_recreate_ranged_hw_breakpoint. */
+ orig_arg = xstrdup (arg);
+ /* We'll only dispose of it if this function is aborted. */
+ cleanup_orig_arg = make_cleanup (xfree, orig_arg);
+
+ sals_start.sals = NULL;
+ sals_start.nelts = 0;
+ addr_string_start = NULL;
+
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+
+ /* We need to use parse_to_comma_and_eval but decode_line_1 uses
+ parse_and_eval_address_1 (see decode_indirect), so we just call it
+ directly if the user provided an explicit PC. */
+ if (arg[0] == '*')
+ {
+ arg++;
+ start_addr = value_as_address (parse_to_comma_and_eval (&arg));
+
+ sals_start.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ sals_start.nelts = 1;
+ sals_start.sals[0] = find_pc_line (start_addr, 0);
+ sals_start.sals[0].pc = start_addr;
+ sals_start.sals[0].section = find_pc_overlay (start_addr);
+ sals_start.sals[0].explicit_pc = 1;
+
+ cleanup_start = make_cleanup (xfree, sals_start.sals);
+ }
+ else
+ {
+
+ parse_breakpoint_sals (&arg, &sals_start, &addr_string_start, NULL);
+
+ cleanup_start = make_cleanup (xfree, sals_start.sals);
+ make_cleanup (xfree, addr_string_start);
+ make_cleanup (xfree, addr_string_start[0]);
+ }
+
+ if (arg[0] != ',')
+ error (_("Too few arguments."));
+ else if (sals_start.nelts == 0)
+ error (_("Could not find location of the beginning of the range."));
+ else if (sals_start.nelts != 1)
+ error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+ breakpoint_sals_to_pc (&sals_start);
+ start_addr = sals_start.sals[0].pc;
+
+ arg++; /* Skip the comma. */
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+
+ /* Parse the end location. */
+
+ sals_end.sals = NULL;
+ sals_end.nelts = 0;
+
+ sals_end = decode_line_1 (&arg, 1, sals_start.sals[0].symtab,
+ sals_start.sals[0].line, 0, 0);
+
+ cleanup_end = make_cleanup (xfree, sals_end.sals);
+
+ if (sals_end.nelts == 0)
+ error (_("Could not find location of the end of the range."));
+ else if (sals_end.nelts != 1)
+ error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+ breakpoint_sals_to_pc (&sals_end);
+
+ /* If the user provided a PC value, use it. Otherwise, find the
+ address of the end of the given location. */
+ if (sals_end.sals[0].explicit_pc)
+ end = sals_end.sals[0].pc;
+ else
+ {
+ ret = find_line_pc_range (sals_end.sals[0], &start, &end);
+ if (!ret)
+ error (_("Could not find location of the end of the range."));
+
+ /* find_line_pc_range returns the start of the next line. */
+ end--;
+ }
+
+ if (start_addr > end)
+ error (_("Invalid address range, end preceeds start."));
+
+ length = end - start_addr + 1;
+ if (length == 1)
+ {
+ /* This range is simple enough to be handled by
+ the `hbreak' command. */
+ hbreak_command (addr_string_start[0], 1);
+
+ do_cleanups (cleanup_orig_arg);
+
+ return;
+ }
+
+ do_cleanups (cleanup_end);
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (gdbarch, sals_start.sals[0], bp_hardware_breakpoint);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->thread = -1;
+ b->disposition = disp_donttouch;
+ b->exp = NULL;
+ b->exp_string = orig_arg;
+ b->val = NULL;
+ b->val_valid = 0;
+ b->ops = &ranged_breakpoint_ops;
+ b->loc->length = length;
+
+ do_cleanups (cleanup_start);
+ discard_cleanups (cleanup_orig_arg);
+
+ mention (b);
+ update_global_location_list (1);
+}
+
/* Return non-zero if EXP is verified as constant. Returned zero
means EXP is variable. Also the constant detection may fail for
some constant expressions and in such case still falsely return
@@ -8392,9 +8767,10 @@ works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
masked hardware watchpoints. */

static enum print_stop_action
-print_it_masked_watchpoint (struct breakpoint *b,
+print_it_masked_watchpoint (const struct bp_location *bl,
const struct value *old_val)
{
+ struct breakpoint *b = bl->owner;
struct ui_stream *stb;
struct cleanup *old_chain;

@@ -8466,10 +8842,12 @@ print_one_detail_masked_watchpoint (const struct breakpoint *b,
masked hardware watchpoints. */

static void
-print_mention_masked_watchpoint (struct breakpoint *b)
+print_mention_masked_watchpoint (struct breakpoint *b, int *say_where)
{
struct cleanup *ui_out_chain;

+ *say_where = 0;
+
switch (b->type)
{
case bp_hardware_watchpoint:
@@ -9292,10 +9670,11 @@ catch_exec_command_1 (char *arg, int from_tty,
}

static enum print_stop_action
-print_it_exception_catchpoint (struct breakpoint *b,
+print_it_exception_catchpoint (const struct bp_location *bl,
const struct value *old_val)
{
int bp_temp, bp_throw;
+ const struct breakpoint *b = bl->owner;

annotate_catchpoint (b->number);

@@ -9325,7 +9704,8 @@ print_it_exception_catchpoint (struct breakpoint *b,

static void
print_one_exception_catchpoint (struct breakpoint *b,
- struct bp_location **last_loc)
+ struct bp_location **last_loc,
+ char *wrap_indent, struct ui_stream *stb)
{
struct value_print_options opts;

@@ -9349,11 +9729,13 @@ print_one_exception_catchpoint (struct breakpoint *b,
}

static void
-print_mention_exception_catchpoint (struct breakpoint *b)
+print_mention_exception_catchpoint (struct breakpoint *b, int *say_where)
{
int bp_temp;
int bp_throw;

+ *say_where = 0;
+
bp_temp = b->disposition == disp_del;
bp_throw = strstr (b->addr_string, "throw") != NULL;
ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
@@ -12830,7 +13212,23 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
&show_always_inserted_mode,
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
-
+
+ add_com ("break-range", class_breakpoint, break_range_command, _("\
+Set a breakpoint for an address range.\n\
+break-range START-LOCATION, END-LOCATION\n\
+where START-LOCATION and END-LOCATION can be one of the following:\n\
+ LINENUM, for that line in the current file,\n\
+ FILE:LINENUM, for that line in that file,\n\
+ +OFFSET, for that number of lines after the current line\n\
+ or the start of the range\n\
+ FUNCTION, for the first line in that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+ *ADDRESS, for the instruction at that address.\n\
+\n\
+The breakpoint will stop execution of the inferior whenever it\n\
+executes any address within the [start-address, end-address] range\n\
+(including START-LOCATION and END-LOCATION)."));
+
automatic_hardware_breakpoints = 1;

observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 3195124..0b19c35 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -29,6 +29,7 @@ struct value;
struct block;
struct breakpoint_object;
struct ui_out;
+struct ui_stream;

/* 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
@@ -218,6 +219,10 @@ struct bp_target_info
is used to determine the type of breakpoint to insert. */
CORE_ADDR placed_address;

+ /* If this is a ranged breakpoint, then this field contains the
+ length of the range that will be watched for execution. */
+ ULONGEST length;
+
/* If the breakpoint lives in memory and reading that memory would
give back the breakpoint, instead of the original contents, then
the original contents are cached here. Only SHADOW_LEN bytes of
@@ -325,8 +330,8 @@ struct bp_location
bp_loc_other. */
CORE_ADDR address;

- /* For hardware watchpoints, the size of data ad ADDRESS being
- watches. */
+ /* For hardware watchpoints, the size of the memory region being watched.
+ For hardware ranged breakpoints, the size of the breakpoint range. */
int length;

/* Type of hardware watchpoint. */
@@ -384,7 +389,8 @@ struct breakpoint_ops

/* Return non-zero if the debugger should tell the user that this
breakpoint was hit. */
- int (*breakpoint_hit) (struct breakpoint *);
+ int (*breakpoint_hit) (const struct bp_location *, struct address_space *,
+ CORE_ADDR);

/* Tell how many hardware resources (debug registers) are needed
for this breakpoint. If this function is not provided, then
@@ -398,12 +404,13 @@ struct breakpoint_ops

/* 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) (const struct bp_location *,
const struct value *old_val);

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

/* Display extra information about this breakpoint, below the normal
breakpoint description in "info breakpoints".
@@ -420,8 +427,10 @@ struct breakpoint_ops
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 *);
+ (roughly speaking; this is called from "mention"). On return,
+ SAY_WHERE will be one if the caller is supposed to print
+ location information about the breakpoint, or zero otherwise. */
+ void (*print_mention) (struct breakpoint *, int *say_where);

/* Print to FP the CLI command that recreates this breakpoint. */
void (*print_recreate) (struct breakpoint *, struct ui_file *fp);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 24d0441..0d0b14c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18724,9 +18724,25 @@ the @code{watch} command (@pxref{Set Watchpoints}), as in:
(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
@end smallexample

+PowerPC embedded processors support hardware accelerated ranged breakpoints.
+A @dfn{ranged breakpoint} stops execution of the inferior whenever it
+executes any address within the range it specifies. To set a ranged
+breakpoint in @value{GDBN}, use the @code{break-range} command.
+
@value{GDBN} provides the following PowerPC-specific commands:

@table @code
+@kindex break-range
+@item break-range @var{start-location}, @var{end-location}
+Set a breakpoint for an address range.
+@var{start-location} and @var{end-location} can specify a function name,
+a line number, an offset of lines from the current line or from the start
+location, or an address of an instruction (@xref{Specify Location},
+for a list of all the possible ways to specify a @var{location}.)
+The breakpoint will stop execution of the inferior whenever it
+executes any address within the specified range, (including
+@var{start-location} and @var{end-location}.)
+
@kindex set powerpc
@item set powerpc soft-float
@itemx show powerpc soft-float
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 140ad97..8b5842b 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1637,6 +1637,19 @@ booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
hw_breaks[i].hw_break = NULL;
}

+/* Return the number of registers needed for a ranged breakpoint. */
+
+static int
+ppc_linux_ranged_break_num_registers (struct target_ops *target)
+{
+ return ((have_ptrace_booke_interface ()
+ && booke_debug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
+ 2 : -1);
+}
+
+/* Insert the hardware breakpoint described by BP_TGT. Returns 0 for
+ success, 1 if hardware breakpoints are not supported or -1 for failure. */
+
static int
ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
@@ -1650,12 +1663,24 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,

p.version = PPC_DEBUG_CURRENT_VERSION;
p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
- p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
p.addr = (uint64_t) bp_tgt->placed_address;
- p.addr2 = 0;
p.condition_value = 0;

+ if (bp_tgt->length)
+ {
+ p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+ /* The breakpoint will trigger if the address of the instruction is
+ within the defined range, as follows: p.addr <= address < p.addr2. */
+ p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+ }
+ else
+ {
+ p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+ p.addr2 = 0;
+ }
+
ALL_LWPS (lp, ptid)
booke_insert_point (&p, TIDGET (ptid));

@@ -1675,12 +1700,24 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,

p.version = PPC_DEBUG_CURRENT_VERSION;
p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
- p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
p.addr = (uint64_t) bp_tgt->placed_address;
- p.addr2 = 0;
p.condition_value = 0;

+ if (bp_tgt->length)
+ {
+ p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+ /* The breakpoint will trigger if the address of the instruction is within
+ the defined range, as follows: p.addr <= address < p.addr2. */
+ p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+ }
+ else
+ {
+ p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+ p.addr2 = 0;
+ }
+
ALL_LWPS (lp, ptid)
booke_remove_point (&p, TIDGET (ptid));

@@ -2468,6 +2505,7 @@ _initialize_ppc_linux_nat (void)
t->to_can_accel_watchpoint_condition
= ppc_linux_can_accel_watchpoint_condition;
t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
+ t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;

t->to_read_description = ppc_linux_read_description;
t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/target.c b/gdb/target.c
index 7a9b3bd..7e54c5e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -598,6 +598,7 @@ update_current_target (void)
INHERIT (to_can_use_hw_breakpoint, t);
INHERIT (to_insert_hw_breakpoint, t);
INHERIT (to_remove_hw_breakpoint, t);
+ /* Do not inherit to_ranged_break_num_registers. */
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
/* Do not inherit to_insert_mask_watchpoint. */
@@ -3429,6 +3430,21 @@ target_masked_watch_num_registers (void)
return return_minus_one ();
}

+/* The documentation for this function is in its prototype declaration
+ in target.h. */
+
+int
+target_ranged_break_num_registers (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_ranged_break_num_registers != NULL)
+ return t->to_ranged_break_num_registers (t);
+
+ return return_minus_one ();
+}
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
diff --git a/gdb/target.h b/gdb/target.h
index e996272..dec0250 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -448,6 +448,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_ranged_break_num_registers) (struct target_ops *);
int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);

@@ -1371,6 +1372,11 @@ extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
#define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
(*current_target.to_remove_hw_breakpoint) (gdbarch, bp_tgt)

+/* Return number of debug registers needed for a ranged breakpoint,
+ or -1 if ranged breakpoints are not supported. */
+
+extern int target_ranged_break_num_registers (void);
+
/* Return non-zero if target knows the data address which triggered this
target_stopped_by_watchpoint, in such case place it to *ADDR_P. Only the
INFERIOR_PTID task is being queried. */
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 53ad963..97b9df0 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -486,6 +486,50 @@ ui_out_field_fmt_int (struct ui_out *uiout,
uo_field_int (uiout, fldno, input_width, input_align, fldname, value);
}

+/* Documented in ui-out.h. */
+
+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);
+}
+
+/* Documented in ui-out.h. */
+
void
ui_out_field_core_addr (struct ui_out *uiout,
const char *fldname,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 4ad0651..098f1bb 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -113,6 +113,16 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
enum ui_align align, const char *fldname,
int value);

+/* Output a field containing a range of addresses. */
+
+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);
+
+/* Output a field containing an addresses. */
+
extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
struct gdbarch *gdbarch, CORE_ADDR address);