2011-03-31 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 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_one_detail>: New method.
	(struct breakpoint) <addr_string_range_end>: New member variable.
	* breakpoint.c (breakpoint_location_address_match): Add function
	prototype.
	(insert_bp_location): Set bl->target_info.length.
	(breakpoint_here_p): Call breakpoint_location_address_match.
	(moribund_breakpoint_here_p): Likewise.
	(regular_breakpoint_inserted_here_p): Likewise.
	(breakpoint_thread_match): Likewise.
	(bpstat_stop_status): Likewise.
	(bpstat_check_location): Move call to
	breakpoint_ops.breakpoint_hit to the top.
	(print_one_breakpoint_location): Call
	breakpoint_ops.print_one_detail if available.
	(breakpoint_address_match_range): New function.
	(breakpoint_location_address_match): Likewise.
	(breakpoint_locations_match): Compare the length field of the
	locations too.
	(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.
	(find_breakpoint_range_end): New function.
	(break_range_command): Likewise.
	(delete_breakpoint): Free addr_string_range_end.
	(update_breakpoint_locations): Add SALS_END argument.  Update
	all callers.  Calculate breakpoint length if a non-zero SALS_END
	is given.  Call breakpoint_locations_match instead of
	breakpoint_address_match.
	(reset_breakpoint): Find SaL of the end of the range if B is a
	ranged breakpoint.
	(_initialize_breakpoint): Register break-range command.
	* defs.h (print_core_address): Add function prototype.
	* 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_core_addr): Move address-printing logic to ...
	* utils.c (print_core_address): ... here.

gdb/doc/
	* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.
This commit is contained in:
Thiago Jung Bauermann 2011-03-31 14:32:49 +00:00
parent bbda34159e
commit f13101077f
14 changed files with 661 additions and 67 deletions

View File

@ -1,3 +1,68 @@
2011-03-31 Thiago Jung Bauermann <bauerman@br.ibm.com>
Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Implement support for PowerPC BookE ranged breakpoints.
* NEWS: Mention support for ranged breakpoints on embedded PowerPC.
* breakpoint.h (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_one_detail>: New method.
(struct breakpoint) <addr_string_range_end>: New member variable.
* breakpoint.c (breakpoint_location_address_match): Add function
prototype.
(insert_bp_location): Set bl->target_info.length.
(breakpoint_here_p): Call breakpoint_location_address_match.
(moribund_breakpoint_here_p): Likewise.
(regular_breakpoint_inserted_here_p): Likewise.
(breakpoint_thread_match): Likewise.
(bpstat_stop_status): Likewise.
(bpstat_check_location): Move call to
breakpoint_ops.breakpoint_hit to the top.
(print_one_breakpoint_location): Call
breakpoint_ops.print_one_detail if available.
(breakpoint_address_match_range): New function.
(breakpoint_location_address_match): Likewise.
(breakpoint_locations_match): Compare the length field of the
locations too.
(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.
(find_breakpoint_range_end): New function.
(break_range_command): Likewise.
(delete_breakpoint): Free addr_string_range_end.
(update_breakpoint_locations): Add SALS_END argument. Update
all callers. Calculate breakpoint length if a non-zero SALS_END
is given. Call breakpoint_locations_match instead of
breakpoint_address_match.
(reset_breakpoint): Find SaL of the end of the range if B is a
ranged breakpoint.
(_initialize_breakpoint): Register break-range command.
* defs.h (print_core_address): Add function prototype.
* 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_core_addr): Move address-printing logic to ...
* utils.c (print_core_address): ... here.
2011-03-31 Ulrich Weigand <uweigand@de.ibm.com>
* breakpoint.c (addr_string_to_sals): Avoid uninitialized

View File

@ -156,6 +156,12 @@
libthread_db library with the "set libthread-db-search-path"
command. See the user manual for more details on this command.
* When natively 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 an instruction
at 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),

View File

@ -10925,6 +10925,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
NULL, /* resources_needed */
print_it_catch_exception,
print_one_catch_exception,
NULL, /* print_one_detail */
print_mention_catch_exception,
print_recreate_catch_exception
};
@ -10964,6 +10965,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
NULL, /* 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
};
@ -11001,6 +11003,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
NULL, /* resources_needed */
print_it_catch_assert,
print_one_catch_assert,
NULL, /* print_one_detail */
print_mention_catch_assert,
print_recreate_catch_assert
};

View File

@ -131,6 +131,10 @@ 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_location_address_match (struct bp_location *bl,
struct address_space *aspace,
CORE_ADDR addr);
static void breakpoints_info (char *, int);
static void watchpoints_info (char *, int);
@ -1537,6 +1541,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)
@ -2799,11 +2804,10 @@ 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_location_address_match (bl, aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bl->section)
@ -2828,8 +2832,7 @@ moribund_breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
int ix;
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
if (breakpoint_address_match (loc->pspace->aspace, loc->address,
aspace, pc))
if (breakpoint_location_address_match (loc, aspace, pc))
return 1;
return 0;
@ -2853,8 +2856,7 @@ regular_breakpoint_inserted_here_p (struct address_space *aspace,
continue;
if (bl->inserted
&& breakpoint_address_match (bl->pspace->aspace, bl->address,
aspace, pc))
&& breakpoint_location_address_match (bl, aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bl->section)
@ -2971,8 +2973,7 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
&& bl->owner->enable_state != bp_permanent)
continue;
if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
aspace, pc))
if (!breakpoint_location_address_match (bl, aspace, pc))
continue;
if (bl->owner->thread != -1)
@ -3860,6 +3861,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))
@ -3888,7 +3892,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)
@ -3899,13 +3903,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;
}
@ -4265,8 +4262,7 @@ bpstat_stop_status (struct address_space *aspace,
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
{
if (breakpoint_address_match (loc->pspace->aspace, loc->address,
aspace, bp_addr))
if (breakpoint_location_address_match (loc, aspace, bp_addr))
{
bs = bpstat_alloc (loc, &bs_link);
/* For hits of moribund locations, we should just proceed. */
@ -4952,9 +4948,12 @@ print_one_breakpoint_location (struct breakpoint *b,
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);
@ -5537,6 +5536,39 @@ 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,
int len1, struct address_space *aspace2,
CORE_ADDR addr2)
{
return ((gdbarch_has_global_breakpoints (target_gdbarch)
|| aspace1 == aspace2)
&& addr2 >= addr1 && addr2 < addr1 + len1);
}
/* Returns true if {ASPACE,ADDR} matches the breakpoint BL. BL may be
a ranged breakpoint. In most targets, a match happens only if ASPACE
matches the breakpoint's address space. On targets that have global
breakpoints, the address space doesn't really matter. */
static int
breakpoint_location_address_match (struct bp_location *bl,
struct address_space *aspace,
CORE_ADDR addr)
{
return (breakpoint_address_match (bl->pspace->aspace, bl->address,
aspace, addr)
|| (bl->length
&& breakpoint_address_match_range (bl->pspace->aspace,
bl->address, bl->length,
aspace, addr)));
}
/* Assuming LOC1 and LOC2's types' have meaningful target addresses
(breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
represent the same location. */
@ -5559,8 +5591,10 @@ breakpoint_locations_match (struct bp_location *loc1,
else if (hw_point1)
return watchpoint_locations_match (loc1, loc2);
else
return breakpoint_address_match (loc1->pspace->aspace, loc1->address,
loc2->pspace->aspace, loc2->address);
/* We compare bp_location.length in order to cover ranged breakpoints. */
return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
loc2->pspace->aspace, loc2->address)
&& loc1->length == loc2->length);
}
static void
@ -6201,9 +6235,10 @@ 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
@ -6272,6 +6307,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
NULL, /* resources_needed */
print_it_catch_fork,
print_one_catch_fork,
NULL, /* print_one_detail */
print_mention_catch_fork,
print_recreate_catch_fork
};
@ -6298,9 +6334,10 @@ 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
@ -6368,6 +6405,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
NULL, /* resources_needed */
print_it_catch_vfork,
print_one_catch_vfork,
NULL, /* print_one_detail */
print_mention_catch_vfork,
print_recreate_catch_vfork
};
@ -6457,12 +6495,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;
@ -6531,7 +6571,7 @@ print_it_catch_syscall (struct breakpoint *b)
static void
print_one_catch_syscall (struct breakpoint *b,
struct bp_location **last_loc)
struct bp_location **last_loc)
{
struct value_print_options opts;
@ -6652,6 +6692,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
NULL, /* resources_needed */
print_it_catch_syscall,
print_one_catch_syscall,
NULL, /* print_one_detail */
print_mention_catch_syscall,
print_recreate_catch_syscall
};
@ -6747,9 +6788,10 @@ 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
@ -6806,6 +6848,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
NULL, /* resources_needed */
print_it_catch_exec,
print_one_catch_exec,
NULL, /* print_one_detail */
print_mention_catch_exec,
print_recreate_catch_exec
};
@ -6829,13 +6872,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;
@ -8303,6 +8355,309 @@ 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 (struct breakpoint *b)
{
struct bp_location *bl = b->loc;
gdb_assert (b->type == bp_hardware_breakpoint);
/* Ranged breakpoints have only one location. */
gdb_assert (bl && bl->next == NULL);
annotate_breakpoint (b->number);
if (b->disposition == disp_del)
ui_out_text (uiout, "\nTemporary 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, ", ");
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)
{
struct bp_location *bl = b->loc;
struct value_print_options opts;
/* Ranged breakpoints have only one location. */
gdb_assert (bl && bl->next == NULL);
get_user_print_options (&opts);
if (opts.addressprint)
/* We don't print the address range here, it will be printed later
by print_one_detail_ranged_breakpoint. */
ui_out_field_skip (uiout, "addr");
annotate_field (5);
print_breakpoint_location (b, bl);
*last_loc = bl;
}
/* 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)
{
CORE_ADDR address_start, address_end;
struct bp_location *bl = b->loc;
struct ui_stream *stb = ui_out_stream_new (uiout);
struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
gdb_assert (bl);
address_start = bl->address;
address_end = address_start + bl->length - 1;
ui_out_text (uiout, "\taddress range: ");
fprintf_unfiltered (stb->stream, "[%s, %s]",
print_core_address (bl->gdbarch, address_start),
print_core_address (bl->gdbarch, address_end));
ui_out_field_stream (uiout, "addr", stb);
ui_out_text (uiout, "\n");
do_cleanups (cleanup);
}
/* Implement the "print_mention" breakpoint_ops method for
ranged breakpoints. */
static void
print_mention_ranged_breakpoint (struct breakpoint *b)
{
struct bp_location *bl = b->loc;
gdb_assert (bl);
gdb_assert (b->type == bp_hardware_breakpoint);
if (ui_out_is_mi_like_p (uiout))
return;
printf_filtered (_("Hardware assisted ranged breakpoint %d from %s to %s."),
b->number, paddress (bl->gdbarch, bl->address),
paddress (bl->gdbarch, bl->address + bl->length - 1));
}
/* 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, %s", b->addr_string,
b->addr_string_range_end);
}
/* 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,
print_it_ranged_breakpoint,
print_one_ranged_breakpoint,
print_one_detail_ranged_breakpoint,
print_mention_ranged_breakpoint,
print_recreate_ranged_breakpoint
};
/* Find the address where the end of the breakpoint range should be
placed, given the SAL of the end of the range. This is so that if
the user provides a line number, the end of the range is set to the
last instruction of the given line. */
static CORE_ADDR
find_breakpoint_range_end (struct symtab_and_line sal)
{
CORE_ADDR end;
/* If the user provided a PC value, use it. Otherwise,
find the address of the end of the given location. */
if (sal.explicit_pc)
end = sal.pc;
else
{
int ret;
CORE_ADDR start;
ret = find_line_pc_range (sal, &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--;
}
return end;
}
/* Implement the "break-range" CLI command. */
static void
break_range_command (char *arg, int from_tty)
{
char *arg_start, *addr_string_start, *addr_string_end;
struct linespec_result canonical_start, canonical_end;
int bp_count, can_use_bp, length;
CORE_ADDR end;
struct breakpoint *b;
struct symtab_and_line sal_start, sal_end;
struct symtabs_and_lines sals_start, sals_end;
struct cleanup *cleanup_bkpt;
/* 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."));
sals_start.sals = NULL;
sals_start.nelts = 0;
init_linespec_result (&canonical_start);
while (*arg == ' ' || *arg == '\t')
arg++;
parse_breakpoint_sals (&arg, &sals_start, &canonical_start, NULL);
sal_start = sals_start.sals[0];
addr_string_start = canonical_start.canonical[0];
cleanup_bkpt = make_cleanup (xfree, addr_string_start);
xfree (sals_start.sals);
xfree (canonical_start.canonical);
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."));
resolve_sal_pc (&sal_start);
arg++; /* Skip the comma. */
while (*arg == ' ' || *arg == '\t')
arg++;
/* Parse the end location. */
sals_end.sals = NULL;
sals_end.nelts = 0;
init_linespec_result (&canonical_end);
arg_start = arg;
/* We call decode_line_n1 directly here instead of using
parse_breakpoint_sals because we need to specify the start location's
symtab and line as the default symtab and line for the end of the
range. This makes it possible to have ranges like "foo.c:27, +14",
where +14 means 14 lines from the start location. */
sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
&canonical_end, NULL);
/* canonical_end can be NULL if it was of the form "*0xdeadbeef". */
if (canonical_end.canonical == NULL)
canonical_end.canonical = xcalloc (1, sizeof (char **));
/* Add the string if not present. */
if (arg_start != arg && canonical_end.canonical[0] == NULL)
canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
sal_end = sals_end.sals[0];
addr_string_end = canonical_end.canonical[0];
make_cleanup (xfree, addr_string_end);
xfree (sals_end.sals);
xfree (canonical_end.canonical);
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."));
resolve_sal_pc (&sal_end);
end = find_breakpoint_range_end (sal_end);
if (sal_start.pc > end)
error (_("Invalid address range, end preceeds start."));
length = end - sal_start.pc + 1;
if (length < 0)
/* Length overflowed. */
error (_("Address range too large."));
else if (length == 1)
{
/* This range is simple enough to be handled by
the `hbreak' command. */
hbreak_command (addr_string_start, 1);
do_cleanups (cleanup_bkpt);
return;
}
/* Now set up the breakpoint. */
b = set_raw_breakpoint (get_current_arch (), sal_start,
bp_hardware_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
b->addr_string = addr_string_start;
b->addr_string_range_end = addr_string_end;
b->ops = &ranged_breakpoint_ops;
b->loc->length = length;
discard_cleanups (cleanup_bkpt);
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
@ -8455,6 +8810,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
resources_needed_watchpoint,
NULL, /* print_it */
NULL, /* print_one */
NULL, /* print_one_detail */
NULL, /* print_mention */
NULL /* print_recreate */
};
@ -9233,6 +9589,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
NULL, /* resources_needed */
print_exception_catchpoint,
print_one_exception_catchpoint,
NULL, /* print_one_detail */
print_mention_exception_catchpoint,
print_recreate_exception_catchpoint
};
@ -10179,6 +10536,7 @@ delete_breakpoint (struct breakpoint *bpt)
xfree (bpt->cond_string);
xfree (bpt->cond_exp);
xfree (bpt->addr_string);
xfree (bpt->addr_string_range_end);
xfree (bpt->exp);
xfree (bpt->exp_string);
xfree (bpt->exp_string_reparse);
@ -10473,14 +10831,21 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
return sal;
}
/* Create new breakpoint locations for B (a hardware or software breakpoint)
based on SALS and SALS_END. If SALS_END.NELTS is not zero, then B is
a ranged breakpoint. */
void
update_breakpoint_locations (struct breakpoint *b,
struct symtabs_and_lines sals)
struct symtabs_and_lines sals,
struct symtabs_and_lines sals_end)
{
int i;
char *s;
struct bp_location *existing_locations = b->loc;
/* Ranged breakpoints have only one start location and one end location. */
gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
/* If there's no new locations, and all existing locations are
pending, don't do anything. This optimizes the common case where
all locations are in the same shared library, that was unloaded.
@ -10501,6 +10866,7 @@ update_breakpoint_locations (struct breakpoint *b,
old symtab. */
if (b->cond_string != NULL)
{
char *s;
struct gdb_exception e;
s = b->cond_string;
@ -10527,6 +10893,13 @@ update_breakpoint_locations (struct breakpoint *b,
if (b->line_number == 0)
b->line_number = sals.sals[i].line;
if (sals_end.nelts)
{
CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
new_loc->length = end - sals.sals[0].pc + 1;
}
}
/* Update locations of permanent breakpoints. */
@ -10552,8 +10925,7 @@ update_breakpoint_locations (struct breakpoint *b,
if (have_ambiguous_names)
{
for (; l; l = l->next)
if (breakpoint_address_match (e->pspace->aspace, e->address,
l->pspace->aspace, l->address))
if (breakpoint_locations_match (e, l))
{
l->enabled = 0;
break;
@ -10673,8 +11045,9 @@ static void
re_set_breakpoint (struct breakpoint *b)
{
int found;
struct symtabs_and_lines sals;
struct symtabs_and_lines sals, sals_end;
struct symtabs_and_lines expanded = {0};
struct symtabs_and_lines expanded_end = {0};
struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
input_radix = b->input_radix;
@ -10689,7 +11062,17 @@ re_set_breakpoint (struct breakpoint *b)
expanded = expand_line_sal_maybe (sals.sals[0]);
}
update_breakpoint_locations (b, expanded);
if (b->addr_string_range_end)
{
sals_end = addr_string_to_sals (b, b->addr_string_range_end, &found);
if (found)
{
make_cleanup (xfree, sals_end.sals);
expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
}
}
update_breakpoint_locations (b, expanded, expanded_end);
do_cleanups (cleanups);
}
@ -12733,7 +13116,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 executes\n\
an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
range (including START-LOCATION and END-LOCATION)."));
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);

View File

@ -231,6 +231,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. */
int 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
@ -339,7 +343,8 @@ struct bp_location
CORE_ADDR address;
/* For hardware watchpoints, the size of the memory region being
watched. */
watched. For hardware ranged breakpoints, the size of the
breakpoint range. */
int length;
/* Type of hardware watchpoint. */
@ -397,7 +402,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
@ -412,6 +418,20 @@ struct breakpoint_ops
breakpoints". */
void (*print_one) (struct breakpoint *, struct bp_location **);
/* Display extra information about this breakpoint, below the normal
breakpoint description in "info breakpoints".
In the example below, the "address range" line was printed
by print_one_detail_ranged_breakpoint.
(gdb) info breakpoints
Num Type Disp Enb Address What
2 hw breakpoint keep y in main at test-watch.c:70
address range: [0x10000458, 0x100004c7]
*/
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 *);
@ -502,6 +522,11 @@ struct breakpoint
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
/* For a ranged breakpoint, the string we used to find
the end of the range (malloc'd). */
char *addr_string_range_end;
/* Architecture we used to set the breakpoint. */
struct gdbarch *gdbarch;
/* Language we used to set the breakpoint. */
@ -904,7 +929,8 @@ extern int breakpoint_thread_match (struct address_space *,
extern void until_break_command (char *, int, int);
extern void update_breakpoint_locations (struct breakpoint *b,
struct symtabs_and_lines sals);
struct symtabs_and_lines sals,
struct symtabs_and_lines sals_end);
extern void breakpoint_re_set (void);

View File

@ -532,6 +532,12 @@ extern const char *host_address_to_string (const void *addr);
This is usually formatted similar to 0x%lx. */
extern const char *paddress (struct gdbarch *gdbarch, CORE_ADDR addr);
/* Return a string representation in hexadecimal notation of ADDRESS,
which is suitable for printing. */
extern const char *print_core_address (struct gdbarch *gdbarch,
CORE_ADDR address);
/* %d for LONGEST */
extern char *plongest (LONGEST l);
/* %u for ULONGEST */

View File

@ -1,3 +1,9 @@
2011-03-31 Thiago Jung Bauermann <bauerman@br.ibm.com>
Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Implement support for PowerPC BookE ranged breakpoints.
* gdb.texinfo (PowerPC Embedded): Document ranged breakpoints.
2011-03-28 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Set Tracepoints): Fix typo.
@ -9,7 +15,7 @@
2011-03-18 Phil Muldoon <pmuldoon@redhat.com>
PR python/12149
PR python/12149
* gdb.texinfo (Basic Python): Update gdb.write and flush text.

View File

@ -18742,9 +18742,27 @@ region using one of the following commands (@pxref{Expressions}):
(@value{GDBP}) watch @{char[@var{length}]@} @var{address}
@end smallexample
@cindex ranged breakpoint
PowerPC embedded processors support hardware accelerated
@dfn{ranged breakpoints}. A ranged breakpoint stops execution of
the inferior whenever it executes an instruction at 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 (see @ref{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 an instruction at 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

View File

@ -1011,7 +1011,7 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
struct value *value;
CORE_ADDR resolved_address, resolved_pc;
struct symtab_and_line sal;
struct symtabs_and_lines sals;
struct symtabs_and_lines sals, sals_end;
gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
@ -1050,9 +1050,10 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
sal = find_pc_line (resolved_pc, 0);
sals.nelts = 1;
sals.sals = &sal;
sals_end.nelts = 0;
b->type = bp_breakpoint;
update_breakpoint_locations (b, sals);
update_breakpoint_locations (b, sals, sals_end);
}
struct build_id

View File

@ -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));
@ -2392,6 +2429,7 @@ _initialize_ppc_linux_nat (void)
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_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;

View File

@ -594,6 +594,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);
INHERIT (to_stopped_data_address, t);
@ -3491,6 +3492,21 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
tcomplain ();
}
/* 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 -1;
}
static void
debug_to_prepare_to_store (struct regcache *regcache)
{

View File

@ -450,6 +450,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 *);
@ -1354,6 +1355,11 @@ extern char *target_thread_name (struct thread_info *);
#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. */

View File

@ -492,23 +492,8 @@ ui_out_field_core_addr (struct ui_out *uiout,
struct gdbarch *gdbarch,
CORE_ADDR address)
{
/* Maximum size string returned by hex_string_custom is 50 chars.
This buffer must be bigger than that, for safety. */
char addstr[64];
int addr_bit = gdbarch_addr_bit (gdbarch);
if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
address &= ((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, hex_string_custom (address, 8));
else
strcpy (addstr, hex_string_custom (address, 16));
ui_out_field_string (uiout, fldname, addstr);
ui_out_field_string (uiout, fldname,
print_core_address (gdbarch, address));
}
void

View File

@ -3224,6 +3224,25 @@ paddress (struct gdbarch *gdbarch, CORE_ADDR addr)
return hex_string (addr);
}
/* This function is described in "defs.h". */
const char *
print_core_address (struct gdbarch *gdbarch, CORE_ADDR address)
{
int addr_bit = gdbarch_addr_bit (gdbarch);
if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
address &= ((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)
return hex_string_custom (address, 8);
else
return hex_string_custom (address, 16);
}
static char *
decimal2str (char *sign, ULONGEST addr, int width)
{