mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-18 16:53:50 +08:00
Put single-step breakpoints on the bp_location chain
This patch makes single-step breakpoints "real" breakpoints on the global location list. There are several benefits to this: - It removes the currently limitation that only 2 single-step breakpoints can be inserted. See an example here of a discussion around a case that wants more than 2, possibly unbounded: https://sourceware.org/ml/gdb-patches/2014-03/msg00663.html - makes software single-step work on read-only code regions. The logic to convert a software breakpoint to a hardware breakpoint if the memory map says the breakpoint address is in read only memory is in insert_bp_location. Because software single-step breakpoints bypass all that go and straight to target_insert_breakpoint, we can't software single-step over read only memory. This patch removes that limitation, and adds a test that makes sure that works, by forcing a code region to read-only with "mem LOW HIGH ro" and then stepping through that. - Fixes PR breakpoints/9649 This is an assertion failure in insert_single_step_breakpoint in breakpoint.c, because we may leave stale single-step breakpoints behind on error. The tests for stepping through read-only regions exercise the root cause of the bug, which is that we leave single-step breakpoints behind if we fail to insert any single-step breakpoint. Deleting the single-step breakpoints in resume_cleanups, delete_just_stopped_threads_infrun_breakpoints, and fetch_inferior_event fixes this. Without that, we'd no longer hit the assertion, as that code is deleted, but we'd instead run into errors/warnings trying to insert/remove the stale breakpoints on next resume. - Paves the way to have multiple threads software single-stepping at the same time, leaving update_global_location_list to worry about duplicate locations. - Makes the moribund location machinery aware of software single-step breakpoints, paving the way to enable software single-step on non-stop, instead of forcing serialized displaced stepping for all single steps. - It's generaly cleaner. We no longer have to play games with single-step breakpoints inserted at the same address as regular breakpoints, like we recently had to do for 7.8. See this discussion: https://sourceware.org/ml/gdb-patches/2014-06/msg00052.html. Tested on x86_64 Fedora 20, on top of my 'single-step breakpoints on x86' series. gdb/ 2014-10-15 Pedro Alves <palves@redhat.com> PR breakpoints/9649 * breakpoint.c (single_step_breakpoints, single_step_gdbarch): Delete array globals. (single_step_breakpoints): New global. (breakpoint_xfer_memory): Remove special handling for single-step breakpoints. (update_breakpoints_after_exec): Delete bp_single_step breakpoints. (detach_breakpoints): Remove special handling for single-step breakpoints. (breakpoint_init_inferior): Delete bp_single_step breakpoints. (bpstat_stop_status): Add comment. (bpstat_what, bptype_string, print_one_breakpoint_location) (adjust_breakpoint_address, init_bp_location): Handle bp_single_step. (new_single_step_breakpoint): New function. (set_momentary_breakpoint, bkpt_remove_location): Remove special handling for single-step breakpoints. (insert_single_step_breakpoint, single_step_breakpoints_inserted) (remove_single_step_breakpoints, cancel_single_step_breakpoints): Rewrite. (detach_single_step_breakpoints, find_single_step_breakpoint): Delete functions. (breakpoint_has_location_inserted_here): New function. (single_step_breakpoint_inserted_here_p): Rewrite. * breakpoint.h: Remove FIXME. (enum bptype) <bp_single_step>: New enum value. (insert_single_step_breakpoint): Update comment. * infrun.c (resume_cleanups) (delete_step_thread_step_resume_breakpoint): Remove single-step breakpoints. (fetch_inferior_event): Install a cleanup that removes infrun breakpoints. (switch_back_to_stepped_thread) <expect thread advanced also>: Clear step-over info. gdb/testsuite/ 2014-10-15 Pedro Alves <palves@redhat.com> PR breakpoints/9649 * gdb.base/breakpoint-in-ro-region.c (main): Add more instructions. * gdb.base/breakpoint-in-ro-region.exp (probe_target_hardware_step): New procedure. (top level): Probe hardware stepping and hardware breakpoint support. Test stepping through a read-only region, with both "breakpoint auto-hw" on and off and both "always-inserted" on and off.
This commit is contained in:
@ -1,3 +1,41 @@
|
|||||||
|
2014-10-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
PR breakpoints/9649
|
||||||
|
* breakpoint.c (single_step_breakpoints, single_step_gdbarch):
|
||||||
|
Delete array globals.
|
||||||
|
(single_step_breakpoints): New global.
|
||||||
|
(breakpoint_xfer_memory): Remove special handling for single-step
|
||||||
|
breakpoints.
|
||||||
|
(update_breakpoints_after_exec): Delete bp_single_step
|
||||||
|
breakpoints.
|
||||||
|
(detach_breakpoints): Remove special handling for single-step
|
||||||
|
breakpoints.
|
||||||
|
(breakpoint_init_inferior): Delete bp_single_step breakpoints.
|
||||||
|
(bpstat_stop_status): Add comment.
|
||||||
|
(bpstat_what, bptype_string, print_one_breakpoint_location)
|
||||||
|
(adjust_breakpoint_address, init_bp_location): Handle
|
||||||
|
bp_single_step.
|
||||||
|
(new_single_step_breakpoint): New function.
|
||||||
|
(set_momentary_breakpoint, bkpt_remove_location): Remove special
|
||||||
|
handling for single-step breakpoints.
|
||||||
|
(insert_single_step_breakpoint, single_step_breakpoints_inserted)
|
||||||
|
(remove_single_step_breakpoints, cancel_single_step_breakpoints):
|
||||||
|
Rewrite.
|
||||||
|
(detach_single_step_breakpoints, find_single_step_breakpoint):
|
||||||
|
Delete functions.
|
||||||
|
(breakpoint_has_location_inserted_here): New function.
|
||||||
|
(single_step_breakpoint_inserted_here_p): Rewrite.
|
||||||
|
* breakpoint.h: Remove FIXME.
|
||||||
|
(enum bptype) <bp_single_step>: New enum value.
|
||||||
|
(insert_single_step_breakpoint): Update comment.
|
||||||
|
* infrun.c (resume_cleanups)
|
||||||
|
(delete_step_thread_step_resume_breakpoint): Remove single-step
|
||||||
|
breakpoints.
|
||||||
|
(fetch_inferior_event): Install a cleanup that removes infrun
|
||||||
|
breakpoints.
|
||||||
|
(switch_back_to_stepped_thread) <expect thread advanced also>:
|
||||||
|
Clear step-over info.
|
||||||
|
|
||||||
2014-10-15 Pedro Alves <palves@redhat.com>
|
2014-10-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
* infrun.c (delete_step_resume_breakpoint_callback): Delete.
|
* infrun.c (delete_step_resume_breakpoint_callback): Delete.
|
||||||
|
224
gdb/breakpoint.c
224
gdb/breakpoint.c
@ -225,11 +225,6 @@ static void stopat_command (char *arg, int from_tty);
|
|||||||
|
|
||||||
static void tcatch_command (char *arg, int from_tty);
|
static void tcatch_command (char *arg, int from_tty);
|
||||||
|
|
||||||
static void detach_single_step_breakpoints (void);
|
|
||||||
|
|
||||||
static int find_single_step_breakpoint (struct address_space *aspace,
|
|
||||||
CORE_ADDR pc);
|
|
||||||
|
|
||||||
static void free_bp_location (struct bp_location *loc);
|
static void free_bp_location (struct bp_location *loc);
|
||||||
static void incref_bp_location (struct bp_location *loc);
|
static void incref_bp_location (struct bp_location *loc);
|
||||||
static void decref_bp_location (struct bp_location **loc);
|
static void decref_bp_location (struct bp_location **loc);
|
||||||
@ -333,8 +328,7 @@ struct breakpoint_ops dprintf_breakpoint_ops;
|
|||||||
/* One (or perhaps two) breakpoints used for software single
|
/* One (or perhaps two) breakpoints used for software single
|
||||||
stepping. */
|
stepping. */
|
||||||
|
|
||||||
static void *single_step_breakpoints[2];
|
static struct breakpoint *single_step_breakpoints;
|
||||||
static struct gdbarch *single_step_gdbarch[2];
|
|
||||||
|
|
||||||
/* The style in which to perform a dynamic printf. This is a user
|
/* The style in which to perform a dynamic printf. This is a user
|
||||||
option because different output options have different tradeoffs;
|
option because different output options have different tradeoffs;
|
||||||
@ -1664,21 +1658,6 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
|
|||||||
one_breakpoint_xfer_memory (readbuf, writebuf, writebuf_org,
|
one_breakpoint_xfer_memory (readbuf, writebuf, writebuf_org,
|
||||||
memaddr, len, &bl->target_info, bl->gdbarch);
|
memaddr, len, &bl->target_info, bl->gdbarch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now process single-step breakpoints. These are not found in the
|
|
||||||
bp_location array. */
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
struct bp_target_info *bp_tgt = single_step_breakpoints[i];
|
|
||||||
|
|
||||||
if (bp_tgt != NULL)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = single_step_gdbarch[i];
|
|
||||||
|
|
||||||
one_breakpoint_xfer_memory (readbuf, writebuf, writebuf_org,
|
|
||||||
memaddr, len, bp_tgt, gdbarch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3792,6 +3771,13 @@ update_breakpoints_after_exec (void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Just like single-step breakpoints. */
|
||||||
|
if (b->type == bp_single_step)
|
||||||
|
{
|
||||||
|
delete_breakpoint (b);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Longjmp and longjmp-resume breakpoints are also meaningless
|
/* Longjmp and longjmp-resume breakpoints are also meaningless
|
||||||
after an exec. */
|
after an exec. */
|
||||||
if (b->type == bp_longjmp || b->type == bp_longjmp_resume
|
if (b->type == bp_longjmp || b->type == bp_longjmp_resume
|
||||||
@ -3884,9 +3870,6 @@ detach_breakpoints (ptid_t ptid)
|
|||||||
val |= remove_breakpoint_1 (bl, mark_inserted);
|
val |= remove_breakpoint_1 (bl, mark_inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detach single-step breakpoints as well. */
|
|
||||||
detach_single_step_breakpoints ();
|
|
||||||
|
|
||||||
do_cleanups (old_chain);
|
do_cleanups (old_chain);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -4156,6 +4139,10 @@ breakpoint_init_inferior (enum inf_context context)
|
|||||||
|
|
||||||
/* Also remove step-resume breakpoints. */
|
/* Also remove step-resume breakpoints. */
|
||||||
|
|
||||||
|
case bp_single_step:
|
||||||
|
|
||||||
|
/* Also remove single-step breakpoints. */
|
||||||
|
|
||||||
delete_breakpoint (b);
|
delete_breakpoint (b);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -5632,6 +5619,7 @@ bpstat_stop_status (struct address_space *aspace,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if a moribund breakpoint explains the stop. */
|
||||||
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
|
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
|
||||||
{
|
{
|
||||||
if (breakpoint_location_address_match (loc, aspace, bp_addr))
|
if (breakpoint_location_address_match (loc, aspace, bp_addr))
|
||||||
@ -5787,6 +5775,7 @@ bpstat_what (bpstat bs_head)
|
|||||||
break;
|
break;
|
||||||
case bp_breakpoint:
|
case bp_breakpoint:
|
||||||
case bp_hardware_breakpoint:
|
case bp_hardware_breakpoint:
|
||||||
|
case bp_single_step:
|
||||||
case bp_until:
|
case bp_until:
|
||||||
case bp_finish:
|
case bp_finish:
|
||||||
case bp_shlib_event:
|
case bp_shlib_event:
|
||||||
@ -6145,6 +6134,7 @@ bptype_string (enum bptype type)
|
|||||||
{bp_none, "?deleted?"},
|
{bp_none, "?deleted?"},
|
||||||
{bp_breakpoint, "breakpoint"},
|
{bp_breakpoint, "breakpoint"},
|
||||||
{bp_hardware_breakpoint, "hw breakpoint"},
|
{bp_hardware_breakpoint, "hw breakpoint"},
|
||||||
|
{bp_single_step, "sw single-step"},
|
||||||
{bp_until, "until"},
|
{bp_until, "until"},
|
||||||
{bp_finish, "finish"},
|
{bp_finish, "finish"},
|
||||||
{bp_watchpoint, "watchpoint"},
|
{bp_watchpoint, "watchpoint"},
|
||||||
@ -6336,6 +6326,7 @@ print_one_breakpoint_location (struct breakpoint *b,
|
|||||||
|
|
||||||
case bp_breakpoint:
|
case bp_breakpoint:
|
||||||
case bp_hardware_breakpoint:
|
case bp_hardware_breakpoint:
|
||||||
|
case bp_single_step:
|
||||||
case bp_until:
|
case bp_until:
|
||||||
case bp_finish:
|
case bp_finish:
|
||||||
case bp_longjmp:
|
case bp_longjmp:
|
||||||
@ -7178,6 +7169,16 @@ adjust_breakpoint_address (struct gdbarch *gdbarch,
|
|||||||
have their addresses modified. */
|
have their addresses modified. */
|
||||||
return bpaddr;
|
return bpaddr;
|
||||||
}
|
}
|
||||||
|
else if (bptype == bp_single_step)
|
||||||
|
{
|
||||||
|
/* Single-step breakpoints should not have their addresses
|
||||||
|
modified. If there's any architectural constrain that
|
||||||
|
applies to this address, then it should have already been
|
||||||
|
taken into account when the breakpoint was created in the
|
||||||
|
first place. If we didn't do this, stepping through e.g.,
|
||||||
|
Thumb-2 IT blocks would break. */
|
||||||
|
return bpaddr;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CORE_ADDR adjusted_bpaddr;
|
CORE_ADDR adjusted_bpaddr;
|
||||||
@ -7214,6 +7215,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
|
|||||||
switch (owner->type)
|
switch (owner->type)
|
||||||
{
|
{
|
||||||
case bp_breakpoint:
|
case bp_breakpoint:
|
||||||
|
case bp_single_step:
|
||||||
case bp_until:
|
case bp_until:
|
||||||
case bp_finish:
|
case bp_finish:
|
||||||
case bp_longjmp:
|
case bp_longjmp:
|
||||||
@ -9196,10 +9198,31 @@ enable_breakpoints_after_startup (void)
|
|||||||
breakpoint_re_set ();
|
breakpoint_re_set ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create a new single-step breakpoint for thread THREAD, with no
|
||||||
|
locations. */
|
||||||
|
|
||||||
/* Set a breakpoint that will evaporate an end of command
|
static struct breakpoint *
|
||||||
at address specified by SAL.
|
new_single_step_breakpoint (int thread, struct gdbarch *gdbarch)
|
||||||
Restrict it to frame FRAME if FRAME is nonzero. */
|
{
|
||||||
|
struct breakpoint *b = XNEW (struct breakpoint);
|
||||||
|
|
||||||
|
init_raw_breakpoint_without_location (b, gdbarch, bp_single_step,
|
||||||
|
&momentary_breakpoint_ops);
|
||||||
|
|
||||||
|
b->disposition = disp_donttouch;
|
||||||
|
b->frame_id = null_frame_id;
|
||||||
|
|
||||||
|
b->thread = thread;
|
||||||
|
gdb_assert (b->thread != 0);
|
||||||
|
|
||||||
|
add_to_breakpoint_chain (b);
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a momentary breakpoint of type TYPE at address specified by
|
||||||
|
SAL. If FRAME_ID is valid, the breakpoint is restricted to that
|
||||||
|
frame. */
|
||||||
|
|
||||||
struct breakpoint *
|
struct breakpoint *
|
||||||
set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal,
|
set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal,
|
||||||
@ -13324,28 +13347,9 @@ static int
|
|||||||
bkpt_insert_location (struct bp_location *bl)
|
bkpt_insert_location (struct bp_location *bl)
|
||||||
{
|
{
|
||||||
if (bl->loc_type == bp_loc_hardware_breakpoint)
|
if (bl->loc_type == bp_loc_hardware_breakpoint)
|
||||||
return target_insert_hw_breakpoint (bl->gdbarch,
|
return target_insert_hw_breakpoint (bl->gdbarch, &bl->target_info);
|
||||||
&bl->target_info);
|
|
||||||
else
|
else
|
||||||
{
|
return target_insert_breakpoint (bl->gdbarch, &bl->target_info);
|
||||||
struct bp_target_info *bp_tgt = &bl->target_info;
|
|
||||||
int ret;
|
|
||||||
int sss_slot;
|
|
||||||
|
|
||||||
/* There is no need to insert a breakpoint if an unconditional
|
|
||||||
raw/sss breakpoint is already inserted at that location. */
|
|
||||||
sss_slot = find_single_step_breakpoint (bp_tgt->placed_address_space,
|
|
||||||
bp_tgt->reqstd_address);
|
|
||||||
if (sss_slot >= 0)
|
|
||||||
{
|
|
||||||
struct bp_target_info *sss_bp_tgt = single_step_breakpoints[sss_slot];
|
|
||||||
|
|
||||||
bp_target_info_copy_insertion_state (bp_tgt, sss_bp_tgt);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return target_insert_breakpoint (bl->gdbarch, bp_tgt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -13354,19 +13358,7 @@ bkpt_remove_location (struct bp_location *bl)
|
|||||||
if (bl->loc_type == bp_loc_hardware_breakpoint)
|
if (bl->loc_type == bp_loc_hardware_breakpoint)
|
||||||
return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
|
return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
|
||||||
else
|
else
|
||||||
{
|
return target_remove_breakpoint (bl->gdbarch, &bl->target_info);
|
||||||
struct bp_target_info *bp_tgt = &bl->target_info;
|
|
||||||
struct address_space *aspace = bp_tgt->placed_address_space;
|
|
||||||
CORE_ADDR address = bp_tgt->reqstd_address;
|
|
||||||
|
|
||||||
/* Only remove the breakpoint if there is no raw/sss breakpoint
|
|
||||||
still inserted at this location. Otherwise, we would be
|
|
||||||
effectively disabling the raw/sss breakpoint. */
|
|
||||||
if (single_step_breakpoint_inserted_here_p (aspace, address))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return target_remove_breakpoint (bl->gdbarch, bp_tgt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -15454,31 +15446,20 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
|
|||||||
struct address_space *aspace,
|
struct address_space *aspace,
|
||||||
CORE_ADDR next_pc)
|
CORE_ADDR next_pc)
|
||||||
{
|
{
|
||||||
void **bpt_p;
|
struct thread_info *tp = inferior_thread ();
|
||||||
|
struct symtab_and_line sal;
|
||||||
|
CORE_ADDR pc = next_pc;
|
||||||
|
|
||||||
if (single_step_breakpoints[0] == NULL)
|
if (single_step_breakpoints == NULL)
|
||||||
{
|
single_step_breakpoints = new_single_step_breakpoint (tp->num, gdbarch);
|
||||||
bpt_p = &single_step_breakpoints[0];
|
|
||||||
single_step_gdbarch[0] = gdbarch;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gdb_assert (single_step_breakpoints[1] == NULL);
|
|
||||||
bpt_p = &single_step_breakpoints[1];
|
|
||||||
single_step_gdbarch[1] = gdbarch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE drow/2006-04-11: A future improvement to this function would
|
sal = find_pc_line (pc, 0);
|
||||||
be to only create the breakpoints once, and actually put them on
|
sal.pc = pc;
|
||||||
the breakpoint chain. That would let us use set_raw_breakpoint.
|
sal.section = find_pc_overlay (pc);
|
||||||
We could adjust the addresses each time they were needed. Doing
|
sal.explicit_pc = 1;
|
||||||
this requires corresponding changes elsewhere where single step
|
add_location_to_breakpoint (single_step_breakpoints, &sal);
|
||||||
breakpoints are handled, however. So, for now, we use this. */
|
|
||||||
|
|
||||||
*bpt_p = deprecated_insert_raw_breakpoint (gdbarch, aspace, next_pc);
|
update_global_location_list (UGLL_INSERT);
|
||||||
if (*bpt_p == NULL)
|
|
||||||
error (_("Could not insert single-step breakpoint at %s"),
|
|
||||||
paddress (gdbarch, next_pc));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the breakpoints used for software single stepping
|
/* Check if the breakpoints used for software single stepping
|
||||||
@ -15487,8 +15468,7 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
|
|||||||
int
|
int
|
||||||
single_step_breakpoints_inserted (void)
|
single_step_breakpoints_inserted (void)
|
||||||
{
|
{
|
||||||
return (single_step_breakpoints[0] != NULL
|
return (single_step_breakpoints != NULL);
|
||||||
|| single_step_breakpoints[1] != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove and delete any breakpoints used for software single step. */
|
/* Remove and delete any breakpoints used for software single step. */
|
||||||
@ -15496,22 +15476,11 @@ single_step_breakpoints_inserted (void)
|
|||||||
void
|
void
|
||||||
remove_single_step_breakpoints (void)
|
remove_single_step_breakpoints (void)
|
||||||
{
|
{
|
||||||
gdb_assert (single_step_breakpoints[0] != NULL);
|
gdb_assert (single_step_breakpoints != NULL);
|
||||||
|
|
||||||
/* See insert_single_step_breakpoint for more about this deprecated
|
delete_breakpoint (single_step_breakpoints);
|
||||||
call. */
|
|
||||||
deprecated_remove_raw_breakpoint (single_step_gdbarch[0],
|
|
||||||
single_step_breakpoints[0]);
|
|
||||||
single_step_gdbarch[0] = NULL;
|
|
||||||
single_step_breakpoints[0] = NULL;
|
|
||||||
|
|
||||||
if (single_step_breakpoints[1] != NULL)
|
single_step_breakpoints = NULL;
|
||||||
{
|
|
||||||
deprecated_remove_raw_breakpoint (single_step_gdbarch[1],
|
|
||||||
single_step_breakpoints[1]);
|
|
||||||
single_step_gdbarch[1] = NULL;
|
|
||||||
single_step_breakpoints[1] = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete software single step breakpoints without removing them from
|
/* Delete software single step breakpoints without removing them from
|
||||||
@ -15522,51 +15491,28 @@ remove_single_step_breakpoints (void)
|
|||||||
void
|
void
|
||||||
cancel_single_step_breakpoints (void)
|
cancel_single_step_breakpoints (void)
|
||||||
{
|
{
|
||||||
int i;
|
/* We don't really need to (or should) delete them here. After an
|
||||||
|
exit, breakpoint_init_inferior deletes it. After an exec,
|
||||||
for (i = 0; i < 2; i++)
|
update_breakpoints_after_exec does it. Just clear our
|
||||||
if (single_step_breakpoints[i])
|
reference. */
|
||||||
{
|
single_step_breakpoints = NULL;
|
||||||
xfree (single_step_breakpoints[i]);
|
|
||||||
single_step_breakpoints[i] = NULL;
|
|
||||||
single_step_gdbarch[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detach software single-step breakpoints from INFERIOR_PTID without
|
/* Check whether any location of BP is inserted at PC. */
|
||||||
removing them. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
detach_single_step_breakpoints (void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
if (single_step_breakpoints[i])
|
|
||||||
target_remove_breakpoint (single_step_gdbarch[i],
|
|
||||||
single_step_breakpoints[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the software single-step breakpoint that inserted at PC.
|
|
||||||
Returns its slot if found, and -1 if not found. */
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
find_single_step_breakpoint (struct address_space *aspace,
|
breakpoint_has_location_inserted_here (struct breakpoint *bp,
|
||||||
|
struct address_space *aspace,
|
||||||
CORE_ADDR pc)
|
CORE_ADDR pc)
|
||||||
{
|
{
|
||||||
int i;
|
struct bp_location *loc;
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
for (loc = bp->loc; loc != NULL; loc = loc->next)
|
||||||
{
|
if (loc->inserted
|
||||||
struct bp_target_info *bp_tgt = single_step_breakpoints[i];
|
&& breakpoint_location_address_match (loc, aspace, pc))
|
||||||
if (bp_tgt
|
return 1;
|
||||||
&& breakpoint_address_match (bp_tgt->placed_address_space,
|
|
||||||
bp_tgt->reqstd_address,
|
|
||||||
aspace, pc))
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check whether a software single-step breakpoint is inserted at
|
/* Check whether a software single-step breakpoint is inserted at
|
||||||
@ -15576,7 +15522,9 @@ int
|
|||||||
single_step_breakpoint_inserted_here_p (struct address_space *aspace,
|
single_step_breakpoint_inserted_here_p (struct address_space *aspace,
|
||||||
CORE_ADDR pc)
|
CORE_ADDR pc)
|
||||||
{
|
{
|
||||||
return find_single_step_breakpoint (aspace, pc) >= 0;
|
return (single_step_breakpoints != NULL
|
||||||
|
&& breakpoint_has_location_inserted_here (single_step_breakpoints,
|
||||||
|
aspace, pc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 0 if 'bp' is NOT a syscall catchpoint,
|
/* Returns 0 if 'bp' is NOT a syscall catchpoint,
|
||||||
|
@ -47,18 +47,13 @@ struct linespec_sals;
|
|||||||
|
|
||||||
|
|
||||||
/* Type of breakpoint. */
|
/* Type of breakpoint. */
|
||||||
/* FIXME In the future, we should fold all other breakpoint-like
|
|
||||||
things into here. This includes:
|
|
||||||
|
|
||||||
* single-step (for machines where we have to simulate single
|
|
||||||
stepping) (probably, though perhaps it is better for it to look as
|
|
||||||
much as possible like a single-step to wait_for_inferior). */
|
|
||||||
|
|
||||||
enum bptype
|
enum bptype
|
||||||
{
|
{
|
||||||
bp_none = 0, /* Eventpoint has been deleted */
|
bp_none = 0, /* Eventpoint has been deleted */
|
||||||
bp_breakpoint, /* Normal breakpoint */
|
bp_breakpoint, /* Normal breakpoint */
|
||||||
bp_hardware_breakpoint, /* Hardware assisted breakpoint */
|
bp_hardware_breakpoint, /* Hardware assisted breakpoint */
|
||||||
|
bp_single_step, /* Software single-step */
|
||||||
bp_until, /* used by until command */
|
bp_until, /* used by until command */
|
||||||
bp_finish, /* used by finish command */
|
bp_finish, /* used by finish command */
|
||||||
bp_watchpoint, /* Watchpoint */
|
bp_watchpoint, /* Watchpoint */
|
||||||
@ -1461,8 +1456,10 @@ extern void add_solib_catchpoint (char *arg, int is_load, int is_temp,
|
|||||||
deletes all breakpoints. */
|
deletes all breakpoints. */
|
||||||
extern void delete_command (char *arg, int from_tty);
|
extern void delete_command (char *arg, int from_tty);
|
||||||
|
|
||||||
/* Manage a software single step breakpoint (or two). Insert may be
|
/* Create and insert a new software single step breakpoint for the
|
||||||
called twice before remove is called. */
|
current thread. May be called multiple times; each time will add a
|
||||||
|
new location to the set of potential addresses the next instruction
|
||||||
|
is at. */
|
||||||
extern void insert_single_step_breakpoint (struct gdbarch *,
|
extern void insert_single_step_breakpoint (struct gdbarch *,
|
||||||
struct address_space *,
|
struct address_space *,
|
||||||
CORE_ADDR);
|
CORE_ADDR);
|
||||||
|
16
gdb/infrun.c
16
gdb/infrun.c
@ -1918,6 +1918,9 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
|
|||||||
static void
|
static void
|
||||||
resume_cleanups (void *ignore)
|
resume_cleanups (void *ignore)
|
||||||
{
|
{
|
||||||
|
if (single_step_breakpoints_inserted ())
|
||||||
|
remove_single_step_breakpoints ();
|
||||||
|
|
||||||
normal_stop ();
|
normal_stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2893,6 +2896,9 @@ static void
|
|||||||
delete_just_stopped_threads_infrun_breakpoints (void)
|
delete_just_stopped_threads_infrun_breakpoints (void)
|
||||||
{
|
{
|
||||||
for_each_just_stopped_thread (delete_thread_infrun_breakpoints);
|
for_each_just_stopped_thread (delete_thread_infrun_breakpoints);
|
||||||
|
|
||||||
|
if (single_step_breakpoints_inserted ())
|
||||||
|
remove_single_step_breakpoints ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A cleanup wrapper. */
|
/* A cleanup wrapper. */
|
||||||
@ -3152,6 +3158,8 @@ fetch_inferior_event (void *client_data)
|
|||||||
still for the thread which has thrown the exception. */
|
still for the thread which has thrown the exception. */
|
||||||
make_bpstat_clear_actions_cleanup ();
|
make_bpstat_clear_actions_cleanup ();
|
||||||
|
|
||||||
|
make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup, NULL);
|
||||||
|
|
||||||
/* Now figure out what to do with the result of the result. */
|
/* Now figure out what to do with the result of the result. */
|
||||||
handle_inferior_event (ecs);
|
handle_inferior_event (ecs);
|
||||||
|
|
||||||
@ -5525,6 +5533,14 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
|
|||||||
fprintf_unfiltered (gdb_stdlog,
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
"infrun: expected thread advanced also\n");
|
"infrun: expected thread advanced also\n");
|
||||||
|
|
||||||
|
/* Clear the info of the previous step-over, as it's no
|
||||||
|
longer valid. It's what keep_going would do too, if
|
||||||
|
we called it. Must do this before trying to insert
|
||||||
|
the sss breakpoint, otherwise if we were previously
|
||||||
|
trying to step over this exact address in another
|
||||||
|
thread, the breakpoint ends up not installed. */
|
||||||
|
clear_step_over_info ();
|
||||||
|
|
||||||
insert_single_step_breakpoint (get_frame_arch (frame),
|
insert_single_step_breakpoint (get_frame_arch (frame),
|
||||||
get_frame_address_space (frame),
|
get_frame_address_space (frame),
|
||||||
stop_pc);
|
stop_pc);
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2014-10-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
PR breakpoints/9649
|
||||||
|
* gdb.base/breakpoint-in-ro-region.c (main): Add more instructions.
|
||||||
|
* gdb.base/breakpoint-in-ro-region.exp
|
||||||
|
(probe_target_hardware_step): New procedure.
|
||||||
|
(top level): Probe hardware stepping and hardware breakpoint
|
||||||
|
support. Test stepping through a read-only region, with both
|
||||||
|
"breakpoint auto-hw" on and off and both "always-inserted" on and
|
||||||
|
off.
|
||||||
|
|
||||||
2014-10-15 Iain Buclaw <ibuclaw@gdcproject.org>
|
2014-10-15 Iain Buclaw <ibuclaw@gdcproject.org>
|
||||||
|
|
||||||
* gdb.dlang/demangle.exp: Update for demangling changes.
|
* gdb.dlang/demangle.exp: Update for demangling changes.
|
||||||
|
@ -23,6 +23,15 @@ main (void)
|
|||||||
i = 0;
|
i = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,28 @@ if ![runto main] {
|
|||||||
|
|
||||||
delete_breakpoints
|
delete_breakpoints
|
||||||
|
|
||||||
|
# Probe for hardware stepping.
|
||||||
|
|
||||||
|
proc probe_target_hardware_step {} {
|
||||||
|
global gdb_prompt
|
||||||
|
|
||||||
|
set hw_step 0
|
||||||
|
|
||||||
|
gdb_test_no_output "set debug target 1"
|
||||||
|
set test "probe target hardware step"
|
||||||
|
gdb_test_multiple "si" $test {
|
||||||
|
-re "to_resume \\(\[^\r\n\]+, step, .*$gdb_prompt $" {
|
||||||
|
set hw_step 1
|
||||||
|
pass $test
|
||||||
|
}
|
||||||
|
-re "$gdb_prompt $" {
|
||||||
|
pass $test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gdb_test "set debug target 0" "->to_log_command.*\\).*"
|
||||||
|
return $hw_step
|
||||||
|
}
|
||||||
|
|
||||||
# Get the bounds of a function, and write them to FUNC_LO (inclusive),
|
# Get the bounds of a function, and write them to FUNC_LO (inclusive),
|
||||||
# FUNC_HI (exclusive). Return true on success and false on failure.
|
# FUNC_HI (exclusive). Return true on success and false on failure.
|
||||||
proc get_function_bounds {function func_lo func_hi} {
|
proc get_function_bounds {function func_lo func_hi} {
|
||||||
@ -108,6 +130,7 @@ proc get_next_insn {} {
|
|||||||
return $next
|
return $next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set hw_step [probe_target_hardware_step]
|
||||||
|
|
||||||
if ![get_function_bounds "main" main_lo main_hi] {
|
if ![get_function_bounds "main" main_lo main_hi] {
|
||||||
# Can't do the following tests if main's bounds are unknown.
|
# Can't do the following tests if main's bounds are unknown.
|
||||||
@ -140,3 +163,84 @@ gdb_test "p /x *(char *) $main_lo = 1" \
|
|||||||
gdb_test "break *$main_lo" \
|
gdb_test "break *$main_lo" \
|
||||||
"Cannot insert breakpoint .*Cannot set software breakpoint at read-only address $main_lo.*" \
|
"Cannot insert breakpoint .*Cannot set software breakpoint at read-only address $main_lo.*" \
|
||||||
"inserting software breakpoint in read-only memory fails"
|
"inserting software breakpoint in read-only memory fails"
|
||||||
|
|
||||||
|
delete_breakpoints
|
||||||
|
|
||||||
|
set supports_hbreak 0
|
||||||
|
set test "probe hbreak support"
|
||||||
|
gdb_test_multiple "hbreak *$main_lo" $test {
|
||||||
|
-re "You may have requested too many.*$gdb_prompt $" {
|
||||||
|
pass "$test (no support)"
|
||||||
|
}
|
||||||
|
-re "No hardware breakpoint support.*$gdb_prompt $" {
|
||||||
|
pass "$test (no support)"
|
||||||
|
}
|
||||||
|
-re "$gdb_prompt $" {
|
||||||
|
pass "$test (support)"
|
||||||
|
set supports_hbreak 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_breakpoints
|
||||||
|
|
||||||
|
# Check that the "auto-hw on/off" setting affects single-step
|
||||||
|
# breakpoints as expected, by stepping through the read-only region.
|
||||||
|
# If the target does hardware stepping, we won't exercise that aspect,
|
||||||
|
# but we should be able to step through the region without seeing the
|
||||||
|
# hardware breakpoint or read-only address errors.
|
||||||
|
proc test_single_step { always_inserted auto_hw } {
|
||||||
|
global gdb_prompt
|
||||||
|
global decimal
|
||||||
|
global supports_hbreak
|
||||||
|
global hw_step
|
||||||
|
|
||||||
|
gdb_test_no_output "set breakpoint always-inserted $always_inserted"
|
||||||
|
gdb_test_no_output "set breakpoint auto-hw $auto_hw"
|
||||||
|
|
||||||
|
# Get the address of the current instruction so we know where SI is
|
||||||
|
# starting from.
|
||||||
|
set curr_insn [get_curr_insn]
|
||||||
|
|
||||||
|
# Get the address of the next instruction so we know where SI should
|
||||||
|
# land.
|
||||||
|
set next_insn [get_next_insn]
|
||||||
|
|
||||||
|
set test "step in ro region"
|
||||||
|
gdb_test_multiple "si" $test {
|
||||||
|
-re "Could not insert hardware breakpoints.*$gdb_prompt $" {
|
||||||
|
gdb_assert {!$hw_step && $auto_hw == "on" && !$supports_hbreak} \
|
||||||
|
"$test (cannot insert hw break)"
|
||||||
|
}
|
||||||
|
-re "Cannot set software breakpoint at read-only address $next_insn.*$gdb_prompt $" {
|
||||||
|
gdb_assert {!$hw_step && $auto_hw == "off"} \
|
||||||
|
"$test (cannot insert sw break)"
|
||||||
|
}
|
||||||
|
-re "^si\r\nNote: automatically using hardware breakpoints for read-only addresses\.\r\n${decimal}\[ \t\]+i = 0;\r\n$gdb_prompt $" {
|
||||||
|
gdb_assert {!$hw_step && $auto_hw == "on" && $supports_hbreak} \
|
||||||
|
"$test (auto-hw)"
|
||||||
|
}
|
||||||
|
-re "^si\r\n${decimal}\[ \t\]+i = 0;\r\n$gdb_prompt $" {
|
||||||
|
gdb_assert {$hw_step || ($auto_hw == "on" && $supports_hbreak)} \
|
||||||
|
"$test (no error)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_test "maint info breakpoints 0" \
|
||||||
|
"No breakpoint or watchpoint matching '0'\." \
|
||||||
|
"single-step breakpoint is not left behind"
|
||||||
|
|
||||||
|
# Confirm the thread really advanced.
|
||||||
|
if {$hw_step || ($auto_hw == "on" && $supports_hbreak)} {
|
||||||
|
gdb_test "p /x \$pc" " = $next_insn" "thread advanced"
|
||||||
|
} else {
|
||||||
|
gdb_test "p /x \$pc" " = $curr_insn" "thread did not advance"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach always_inserted {"off" "on"} {
|
||||||
|
foreach auto_hw {"off" "on"} {
|
||||||
|
with_test_prefix "always-inserted $always_inserted: auto-hw $auto_hw" {
|
||||||
|
test_single_step $always_inserted $auto_hw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user