Make single-step breakpoints be per-thread
This patch finally makes each thread have its own set of single-step breakpoints. This paves the way to have multiple threads software single-stepping, though this patch doesn't flip that switch on yet. That'll be done on a subsequent patch. gdb/ 2014-10-15 Pedro Alves <palves@redhat.com> * breakpoint.c (single_step_breakpoints): Delete global. (insert_single_step_breakpoint): Adjust to store the breakpoint pointer in the current thread. (single_step_breakpoints_inserted, remove_single_step_breakpoints) (cancel_single_step_breakpoints): Delete functions. (breakpoint_has_location_inserted_here): Make extern. (single_step_breakpoint_inserted_here_p): Adjust to walk the breakpoint list. * breakpoint.h (breakpoint_has_location_inserted_here): New declaration. (single_step_breakpoints_inserted, remove_single_step_breakpoints) (cancel_single_step_breakpoints): Remove declarations. * gdbthread.h (struct thread_control_state) <single_step_breakpoints>: New field. (delete_single_step_breakpoints) (thread_has_single_step_breakpoints_set) (thread_has_single_step_breakpoint_here): New declarations. * infrun.c (follow_exec): Also clear the single-step breakpoints. (singlestep_breakpoints_inserted_p, singlestep_ptid) (singlestep_pc): Delete globals. (infrun_thread_ptid_changed): Remove references to removed globals. (resume_cleanups): Delete the current thread's single-step breakpoints. (maybe_software_singlestep): Remove references to removed globals. (resume): Adjust to use thread_has_single_step_breakpoints_set and delete_single_step_breakpoints. (init_wait_for_inferior): Remove references to removed globals. (delete_thread_infrun_breakpoints): Delete the thread's single-step breakpoints too. (delete_just_stopped_threads_infrun_breakpoints): Don't delete single-step breakpoints here. (delete_stopped_threads_single_step_breakpoints): New function. (adjust_pc_after_break): Adjust to use thread_has_single_step_breakpoints_set. (handle_inferior_event): Remove references to removed globals. Use delete_stopped_threads_single_step_breakpoints. (handle_signal_stop): Adjust to per-thread single-step breakpoints. Swap test order to do cheaper tests first. (switch_back_to_stepped_thread): Extend debug output. Remove references to removed globals. * record-full.c (record_full_wait_1): Adjust to per-thread single-step breakpoints. * thread.c (delete_single_step_breakpoints) (thread_has_single_step_breakpoints_set) (thread_has_single_step_breakpoint_here): New functions. (clear_thread_inferior_resources): Also delete the thread's single-step breakpoints.
This commit is contained in:
parent
5b834a0a5d
commit
34b7e8a6ad
@ -1,3 +1,54 @@
|
||||
2014-10-15 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* breakpoint.c (single_step_breakpoints): Delete global.
|
||||
(insert_single_step_breakpoint): Adjust to store the breakpoint
|
||||
pointer in the current thread.
|
||||
(single_step_breakpoints_inserted, remove_single_step_breakpoints)
|
||||
(cancel_single_step_breakpoints): Delete functions.
|
||||
(breakpoint_has_location_inserted_here): Make extern.
|
||||
(single_step_breakpoint_inserted_here_p): Adjust to walk the
|
||||
breakpoint list.
|
||||
* breakpoint.h (breakpoint_has_location_inserted_here): New
|
||||
declaration.
|
||||
(single_step_breakpoints_inserted, remove_single_step_breakpoints)
|
||||
(cancel_single_step_breakpoints): Remove declarations.
|
||||
* gdbthread.h (struct thread_control_state)
|
||||
<single_step_breakpoints>: New field.
|
||||
(delete_single_step_breakpoints)
|
||||
(thread_has_single_step_breakpoints_set)
|
||||
(thread_has_single_step_breakpoint_here): New declarations.
|
||||
* infrun.c (follow_exec): Also clear the single-step breakpoints.
|
||||
(singlestep_breakpoints_inserted_p, singlestep_ptid)
|
||||
(singlestep_pc): Delete globals.
|
||||
(infrun_thread_ptid_changed): Remove references to removed
|
||||
globals.
|
||||
(resume_cleanups): Delete the current thread's single-step
|
||||
breakpoints.
|
||||
(maybe_software_singlestep): Remove references to removed globals.
|
||||
(resume): Adjust to use thread_has_single_step_breakpoints_set and
|
||||
delete_single_step_breakpoints.
|
||||
(init_wait_for_inferior): Remove references to removed globals.
|
||||
(delete_thread_infrun_breakpoints): Delete the thread's
|
||||
single-step breakpoints too.
|
||||
(delete_just_stopped_threads_infrun_breakpoints): Don't delete
|
||||
single-step breakpoints here.
|
||||
(delete_stopped_threads_single_step_breakpoints): New function.
|
||||
(adjust_pc_after_break): Adjust to use
|
||||
thread_has_single_step_breakpoints_set.
|
||||
(handle_inferior_event): Remove references to removed globals.
|
||||
Use delete_stopped_threads_single_step_breakpoints.
|
||||
(handle_signal_stop): Adjust to per-thread single-step
|
||||
breakpoints. Swap test order to do cheaper tests first.
|
||||
(switch_back_to_stepped_thread): Extend debug output. Remove
|
||||
references to removed globals.
|
||||
* record-full.c (record_full_wait_1): Adjust to per-thread
|
||||
single-step breakpoints.
|
||||
* thread.c (delete_single_step_breakpoints)
|
||||
(thread_has_single_step_breakpoints_set)
|
||||
(thread_has_single_step_breakpoint_here): New functions.
|
||||
(clear_thread_inferior_resources): Also delete the thread's
|
||||
single-step breakpoints.
|
||||
|
||||
2014-10-15 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* thread.c (delete_thread_breakpoint): New function.
|
||||
|
@ -325,11 +325,6 @@ static struct breakpoint_ops bkpt_probe_breakpoint_ops;
|
||||
/* Dynamic printf class type. */
|
||||
struct breakpoint_ops dprintf_breakpoint_ops;
|
||||
|
||||
/* One (or perhaps two) breakpoints used for software single
|
||||
stepping. */
|
||||
|
||||
static struct breakpoint *single_step_breakpoints;
|
||||
|
||||
/* The style in which to perform a dynamic printf. This is a user
|
||||
option because different output options have different tradeoffs;
|
||||
if GDB does the printing, there is better error handling if there
|
||||
@ -15319,57 +15314,24 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
|
||||
struct symtab_and_line sal;
|
||||
CORE_ADDR pc = next_pc;
|
||||
|
||||
if (single_step_breakpoints == NULL)
|
||||
single_step_breakpoints = new_single_step_breakpoint (tp->num, gdbarch);
|
||||
if (tp->control.single_step_breakpoints == NULL)
|
||||
{
|
||||
tp->control.single_step_breakpoints
|
||||
= new_single_step_breakpoint (tp->num, gdbarch);
|
||||
}
|
||||
|
||||
sal = find_pc_line (pc, 0);
|
||||
sal.pc = pc;
|
||||
sal.section = find_pc_overlay (pc);
|
||||
sal.explicit_pc = 1;
|
||||
add_location_to_breakpoint (single_step_breakpoints, &sal);
|
||||
add_location_to_breakpoint (tp->control.single_step_breakpoints, &sal);
|
||||
|
||||
update_global_location_list (UGLL_INSERT);
|
||||
}
|
||||
|
||||
/* Check if the breakpoints used for software single stepping
|
||||
were inserted or not. */
|
||||
/* See breakpoint.h. */
|
||||
|
||||
int
|
||||
single_step_breakpoints_inserted (void)
|
||||
{
|
||||
return (single_step_breakpoints != NULL);
|
||||
}
|
||||
|
||||
/* Remove and delete any breakpoints used for software single step. */
|
||||
|
||||
void
|
||||
remove_single_step_breakpoints (void)
|
||||
{
|
||||
gdb_assert (single_step_breakpoints != NULL);
|
||||
|
||||
delete_breakpoint (single_step_breakpoints);
|
||||
|
||||
single_step_breakpoints = NULL;
|
||||
}
|
||||
|
||||
/* Delete software single step breakpoints without removing them from
|
||||
the inferior. This is intended to be used if the inferior's address
|
||||
space where they were inserted is already gone, e.g. after exit or
|
||||
exec. */
|
||||
|
||||
void
|
||||
cancel_single_step_breakpoints (void)
|
||||
{
|
||||
/* We don't really need to (or should) delete them here. After an
|
||||
exit, breakpoint_init_inferior deletes it. After an exec,
|
||||
update_breakpoints_after_exec does it. Just clear our
|
||||
reference. */
|
||||
single_step_breakpoints = NULL;
|
||||
}
|
||||
|
||||
/* Check whether any location of BP is inserted at PC. */
|
||||
|
||||
static int
|
||||
breakpoint_has_location_inserted_here (struct breakpoint *bp,
|
||||
struct address_space *aspace,
|
||||
CORE_ADDR pc)
|
||||
@ -15391,9 +15353,15 @@ int
|
||||
single_step_breakpoint_inserted_here_p (struct address_space *aspace,
|
||||
CORE_ADDR pc)
|
||||
{
|
||||
return (single_step_breakpoints != NULL
|
||||
&& breakpoint_has_location_inserted_here (single_step_breakpoints,
|
||||
aspace, pc));
|
||||
struct breakpoint *bpt;
|
||||
|
||||
ALL_BREAKPOINTS (bpt)
|
||||
{
|
||||
if (bpt->type == bp_single_step
|
||||
&& breakpoint_has_location_inserted_here (bpt, aspace, pc))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 if 'bp' is NOT a syscall catchpoint,
|
||||
|
@ -1129,6 +1129,12 @@ extern int regular_breakpoint_inserted_here_p (struct address_space *,
|
||||
extern int software_breakpoint_inserted_here_p (struct address_space *,
|
||||
CORE_ADDR);
|
||||
|
||||
/* Check whether any location of BP is inserted at PC. */
|
||||
|
||||
extern int breakpoint_has_location_inserted_here (struct breakpoint *bp,
|
||||
struct address_space *aspace,
|
||||
CORE_ADDR pc);
|
||||
|
||||
extern int single_step_breakpoint_inserted_here_p (struct address_space *,
|
||||
CORE_ADDR);
|
||||
|
||||
@ -1463,10 +1469,6 @@ extern void delete_command (char *arg, int from_tty);
|
||||
extern void insert_single_step_breakpoint (struct gdbarch *,
|
||||
struct address_space *,
|
||||
CORE_ADDR);
|
||||
extern int single_step_breakpoints_inserted (void);
|
||||
extern void remove_single_step_breakpoints (void);
|
||||
extern void cancel_single_step_breakpoints (void);
|
||||
|
||||
/* Check if any hardware watchpoints have triggered, according to the
|
||||
target. */
|
||||
int watchpoints_triggered (struct target_waitstatus *);
|
||||
|
@ -52,6 +52,13 @@ struct thread_control_state
|
||||
/* Exception-resume breakpoint. */
|
||||
struct breakpoint *exception_resume_breakpoint;
|
||||
|
||||
/* Breakpoints used for software single stepping. Plural, because
|
||||
it may have multiple locations. E.g., if stepping over a
|
||||
conditional branch instruction we can't decode the condition for,
|
||||
we'll need to put a breakpoint at the branch destination, and
|
||||
another at the instruction after the branch. */
|
||||
struct breakpoint *single_step_breakpoints;
|
||||
|
||||
/* Range to single step within.
|
||||
|
||||
If this is nonzero, respond to a single-step signal by continuing
|
||||
@ -285,6 +292,19 @@ extern void delete_step_resume_breakpoint (struct thread_info *);
|
||||
/* Delete an exception_resume_breakpoint from the thread database. */
|
||||
extern void delete_exception_resume_breakpoint (struct thread_info *);
|
||||
|
||||
/* Delete the single-step breakpoints of thread TP, if any. */
|
||||
extern void delete_single_step_breakpoints (struct thread_info *tp);
|
||||
|
||||
/* Check if the thread has software single stepping breakpoints
|
||||
set. */
|
||||
extern int thread_has_single_step_breakpoints_set (struct thread_info *tp);
|
||||
|
||||
/* Check whether the thread has software single stepping breakpoints
|
||||
set at PC. */
|
||||
extern int thread_has_single_step_breakpoint_here (struct thread_info *tp,
|
||||
struct address_space *aspace,
|
||||
CORE_ADDR addr);
|
||||
|
||||
/* Translate the integer thread id (GDB's homegrown id, not the system's)
|
||||
into a "pid" (which may be overloaded with extra thread information). */
|
||||
extern ptid_t thread_id_to_pid (int);
|
||||
|
113
gdb/infrun.c
113
gdb/infrun.c
@ -1082,6 +1082,7 @@ follow_exec (ptid_t pid, char *execd_pathname)
|
||||
statement through an exec(). */
|
||||
th->control.step_resume_breakpoint = NULL;
|
||||
th->control.exception_resume_breakpoint = NULL;
|
||||
th->control.single_step_breakpoints = NULL;
|
||||
th->control.step_range_start = 0;
|
||||
th->control.step_range_end = 0;
|
||||
|
||||
@ -1195,17 +1196,6 @@ follow_exec (ptid_t pid, char *execd_pathname)
|
||||
matically get reset there in the new process.). */
|
||||
}
|
||||
|
||||
/* Non-zero if we just simulating a single-step. This is needed
|
||||
because we cannot remove the breakpoints in the inferior process
|
||||
until after the `wait' in `wait_for_inferior'. */
|
||||
static int singlestep_breakpoints_inserted_p = 0;
|
||||
|
||||
/* The thread we inserted single-step breakpoints for. */
|
||||
static ptid_t singlestep_ptid;
|
||||
|
||||
/* PC when we started this single-step. */
|
||||
static CORE_ADDR singlestep_pc;
|
||||
|
||||
/* Info about an instruction that is being stepped over. */
|
||||
|
||||
struct step_over_info
|
||||
@ -1895,9 +1885,6 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
|
||||
if (ptid_equal (inferior_ptid, old_ptid))
|
||||
inferior_ptid = new_ptid;
|
||||
|
||||
if (ptid_equal (singlestep_ptid, old_ptid))
|
||||
singlestep_ptid = new_ptid;
|
||||
|
||||
for (displaced = displaced_step_inferior_states;
|
||||
displaced;
|
||||
displaced = displaced->next)
|
||||
@ -1918,8 +1905,8 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
|
||||
static void
|
||||
resume_cleanups (void *ignore)
|
||||
{
|
||||
if (single_step_breakpoints_inserted ())
|
||||
remove_single_step_breakpoints ();
|
||||
if (!ptid_equal (inferior_ptid, null_ptid))
|
||||
delete_single_step_breakpoints (inferior_thread ());
|
||||
|
||||
normal_stop ();
|
||||
}
|
||||
@ -1975,11 +1962,6 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
&& gdbarch_software_single_step (gdbarch, get_current_frame ()))
|
||||
{
|
||||
hw_step = 0;
|
||||
/* Do not pull these breakpoints until after a `wait' in
|
||||
`wait_for_inferior'. */
|
||||
singlestep_breakpoints_inserted_p = 1;
|
||||
singlestep_ptid = inferior_ptid;
|
||||
singlestep_pc = pc;
|
||||
}
|
||||
return hw_step;
|
||||
}
|
||||
@ -2167,7 +2149,7 @@ a command like `return' or `jump' to continue execution."));
|
||||
at the current address, deliver the signal without stepping, and
|
||||
once we arrive back at the step-resume breakpoint, actually step
|
||||
over the breakpoint we originally wanted to step over. */
|
||||
if (singlestep_breakpoints_inserted_p
|
||||
if (thread_has_single_step_breakpoints_set (tp)
|
||||
&& sig != GDB_SIGNAL_0
|
||||
&& step_over_info_valid_p ())
|
||||
{
|
||||
@ -2182,8 +2164,7 @@ a command like `return' or `jump' to continue execution."));
|
||||
tp->step_after_step_resume_breakpoint = 1;
|
||||
}
|
||||
|
||||
remove_single_step_breakpoints ();
|
||||
singlestep_breakpoints_inserted_p = 0;
|
||||
delete_single_step_breakpoints (tp);
|
||||
|
||||
clear_step_over_info ();
|
||||
tp->control.trap_expected = 0;
|
||||
@ -2194,7 +2175,7 @@ a command like `return' or `jump' to continue execution."));
|
||||
/* If STEP is set, it's a request to use hardware stepping
|
||||
facilities. But in that case, we should never
|
||||
use singlestep breakpoint. */
|
||||
gdb_assert (!(singlestep_breakpoints_inserted_p && step));
|
||||
gdb_assert (!(thread_has_single_step_breakpoints_set (tp) && step));
|
||||
|
||||
/* Decide the set of threads to ask the target to resume. Start
|
||||
by assuming everything will be resumed, than narrow the set
|
||||
@ -2210,7 +2191,7 @@ a command like `return' or `jump' to continue execution."));
|
||||
set_running (resume_ptid, 1);
|
||||
|
||||
/* Maybe resume a single thread after all. */
|
||||
if ((step || singlestep_breakpoints_inserted_p)
|
||||
if ((step || thread_has_single_step_breakpoints_set (tp))
|
||||
&& tp->control.trap_expected)
|
||||
{
|
||||
/* We're allowing a thread to run past a breakpoint it has
|
||||
@ -2679,9 +2660,6 @@ init_wait_for_inferior (void)
|
||||
|
||||
/* Discard any skipped inlined frames. */
|
||||
clear_inline_frame_state (minus_one_ptid);
|
||||
|
||||
singlestep_ptid = null_ptid;
|
||||
singlestep_pc = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2857,6 +2835,7 @@ delete_thread_infrun_breakpoints (struct thread_info *tp)
|
||||
{
|
||||
delete_step_resume_breakpoint (tp);
|
||||
delete_exception_resume_breakpoint (tp);
|
||||
delete_single_step_breakpoints (tp);
|
||||
}
|
||||
|
||||
/* If the target still has execution, call FUNC for each thread that
|
||||
@ -2896,9 +2875,15 @@ static void
|
||||
delete_just_stopped_threads_infrun_breakpoints (void)
|
||||
{
|
||||
for_each_just_stopped_thread (delete_thread_infrun_breakpoints);
|
||||
}
|
||||
|
||||
if (single_step_breakpoints_inserted ())
|
||||
remove_single_step_breakpoints ();
|
||||
/* Delete the single-step breakpoints of the threads that just
|
||||
stopped. */
|
||||
|
||||
static void
|
||||
delete_just_stopped_threads_single_step_breakpoints (void)
|
||||
{
|
||||
for_each_just_stopped_thread (delete_single_step_breakpoints);
|
||||
}
|
||||
|
||||
/* A cleanup wrapper. */
|
||||
@ -3386,7 +3371,7 @@ adjust_pc_after_break (struct execution_control_state *ecs)
|
||||
software breakpoint. In this case (prev_pc == breakpoint_pc),
|
||||
we also need to back up to the breakpoint address. */
|
||||
|
||||
if (singlestep_breakpoints_inserted_p
|
||||
if (thread_has_single_step_breakpoints_set (ecs->event_thread)
|
||||
|| !ptid_equal (ecs->ptid, inferior_ptid)
|
||||
|| !currently_stepping (ecs->event_thread)
|
||||
|| ecs->event_thread->prev_pc == breakpoint_pc)
|
||||
@ -3772,8 +3757,6 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
|
||||
|
||||
gdb_flush (gdb_stdout);
|
||||
target_mourn_inferior ();
|
||||
singlestep_breakpoints_inserted_p = 0;
|
||||
cancel_single_step_breakpoints ();
|
||||
stop_print_frame = 0;
|
||||
stop_waiting (ecs);
|
||||
return;
|
||||
@ -3866,12 +3849,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
|
||||
detach_breakpoints (ecs->ws.value.related_pid);
|
||||
}
|
||||
|
||||
if (singlestep_breakpoints_inserted_p)
|
||||
{
|
||||
/* Pull the single step breakpoints out of the target. */
|
||||
remove_single_step_breakpoints ();
|
||||
singlestep_breakpoints_inserted_p = 0;
|
||||
}
|
||||
delete_just_stopped_threads_single_step_breakpoints ();
|
||||
|
||||
/* In case the event is caught by a catchpoint, remember that
|
||||
the event is to be followed at the next resume of the thread,
|
||||
@ -3958,9 +3936,6 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
|
||||
if (!ptid_equal (ecs->ptid, inferior_ptid))
|
||||
context_switch (ecs->ptid);
|
||||
|
||||
singlestep_breakpoints_inserted_p = 0;
|
||||
cancel_single_step_breakpoints ();
|
||||
|
||||
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
|
||||
|
||||
/* Do whatever is necessary to the parent branch of the vfork. */
|
||||
@ -4026,14 +4001,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n");
|
||||
/* Reverse execution: target ran out of history info. */
|
||||
|
||||
/* Pull the single step breakpoints out of the target. */
|
||||
if (singlestep_breakpoints_inserted_p)
|
||||
{
|
||||
if (!ptid_equal (ecs->ptid, inferior_ptid))
|
||||
context_switch (ecs->ptid);
|
||||
remove_single_step_breakpoints ();
|
||||
singlestep_breakpoints_inserted_p = 0;
|
||||
}
|
||||
delete_just_stopped_threads_single_step_breakpoints ();
|
||||
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
|
||||
observer_notify_no_history ();
|
||||
stop_waiting (ecs);
|
||||
@ -4172,13 +4140,9 @@ handle_signal_stop (struct execution_control_state *ecs)
|
||||
gdbarch = get_frame_arch (frame);
|
||||
|
||||
/* Pull the single step breakpoints out of the target. */
|
||||
if (singlestep_breakpoints_inserted_p)
|
||||
if (gdbarch_software_single_step_p (gdbarch))
|
||||
{
|
||||
/* However, before doing so, if this single-step breakpoint was
|
||||
actually for another thread, set this thread up for moving
|
||||
past it. */
|
||||
if (!ptid_equal (ecs->ptid, singlestep_ptid)
|
||||
&& ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
|
||||
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
|
||||
{
|
||||
struct regcache *regcache;
|
||||
struct address_space *aspace;
|
||||
@ -4187,22 +4151,38 @@ handle_signal_stop (struct execution_control_state *ecs)
|
||||
regcache = get_thread_regcache (ecs->ptid);
|
||||
aspace = get_regcache_aspace (regcache);
|
||||
pc = regcache_read_pc (regcache);
|
||||
if (single_step_breakpoint_inserted_here_p (aspace, pc))
|
||||
|
||||
/* However, before doing so, if this single-step breakpoint was
|
||||
actually for another thread, set this thread up for moving
|
||||
past it. */
|
||||
if (!thread_has_single_step_breakpoint_here (ecs->event_thread,
|
||||
aspace, pc))
|
||||
{
|
||||
if (single_step_breakpoint_inserted_here_p (aspace, pc))
|
||||
{
|
||||
if (debug_infrun)
|
||||
{
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"infrun: [%s] hit another thread's "
|
||||
"single-step breakpoint\n",
|
||||
target_pid_to_str (ecs->ptid));
|
||||
}
|
||||
ecs->hit_singlestep_breakpoint = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (debug_infrun)
|
||||
{
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"infrun: [%s] hit step over single-step"
|
||||
" breakpoint of [%s]\n",
|
||||
target_pid_to_str (ecs->ptid),
|
||||
target_pid_to_str (singlestep_ptid));
|
||||
"infrun: [%s] hit its "
|
||||
"single-step breakpoint\n",
|
||||
target_pid_to_str (ecs->ptid));
|
||||
}
|
||||
ecs->hit_singlestep_breakpoint = 1;
|
||||
}
|
||||
}
|
||||
|
||||
remove_single_step_breakpoints ();
|
||||
singlestep_breakpoints_inserted_p = 0;
|
||||
delete_just_stopped_threads_single_step_breakpoints ();
|
||||
}
|
||||
|
||||
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
||||
@ -5544,10 +5524,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
|
||||
insert_single_step_breakpoint (get_frame_arch (frame),
|
||||
get_frame_address_space (frame),
|
||||
stop_pc);
|
||||
singlestep_breakpoints_inserted_p = 1;
|
||||
ecs->event_thread->control.trap_expected = 1;
|
||||
singlestep_ptid = inferior_ptid;
|
||||
singlestep_pc = stop_pc;
|
||||
|
||||
resume (0, GDB_SIGNAL_0);
|
||||
prepare_to_wait (ecs);
|
||||
|
@ -960,7 +960,7 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
|
||||
else
|
||||
{
|
||||
/* This arch support soft sigle step. */
|
||||
if (single_step_breakpoints_inserted ())
|
||||
if (thread_has_single_step_breakpoints_set (inferior_thread ()))
|
||||
{
|
||||
/* This is a soft single step. */
|
||||
record_full_resume_step = 1;
|
||||
@ -1084,6 +1084,8 @@ record_full_wait_1 (struct target_ops *ops,
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct thread_info *tp;
|
||||
|
||||
ret = ops->beneath->to_wait (ops->beneath, ptid, status, options);
|
||||
if (status->kind == TARGET_WAITKIND_IGNORE)
|
||||
{
|
||||
@ -1094,8 +1096,8 @@ record_full_wait_1 (struct target_ops *ops,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (single_step_breakpoints_inserted ())
|
||||
remove_single_step_breakpoints ();
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
delete_single_step_breakpoints (tp);
|
||||
|
||||
if (record_full_resume_step)
|
||||
return ret;
|
||||
|
31
gdb/thread.c
31
gdb/thread.c
@ -117,6 +117,15 @@ delete_exception_resume_breakpoint (struct thread_info *tp)
|
||||
delete_thread_breakpoint (&tp->control.exception_resume_breakpoint);
|
||||
}
|
||||
|
||||
/* See gdbthread.h. */
|
||||
|
||||
void
|
||||
delete_single_step_breakpoints (struct thread_info *tp)
|
||||
{
|
||||
if (tp != NULL)
|
||||
delete_thread_breakpoint (&tp->control.single_step_breakpoints);
|
||||
}
|
||||
|
||||
/* Delete the breakpoint pointed at by BP_P at the next stop, if
|
||||
there's one. */
|
||||
|
||||
@ -130,6 +139,27 @@ delete_at_next_stop (struct breakpoint **bp)
|
||||
}
|
||||
}
|
||||
|
||||
/* See gdbthread.h. */
|
||||
|
||||
int
|
||||
thread_has_single_step_breakpoints_set (struct thread_info *tp)
|
||||
{
|
||||
return tp->control.single_step_breakpoints != NULL;
|
||||
}
|
||||
|
||||
/* See gdbthread.h. */
|
||||
|
||||
int
|
||||
thread_has_single_step_breakpoint_here (struct thread_info *tp,
|
||||
struct address_space *aspace,
|
||||
CORE_ADDR addr)
|
||||
{
|
||||
struct breakpoint *ss_bps = tp->control.single_step_breakpoints;
|
||||
|
||||
return (ss_bps != NULL
|
||||
&& breakpoint_has_location_inserted_here (ss_bps, aspace, addr));
|
||||
}
|
||||
|
||||
static void
|
||||
clear_thread_inferior_resources (struct thread_info *tp)
|
||||
{
|
||||
@ -139,6 +169,7 @@ clear_thread_inferior_resources (struct thread_info *tp)
|
||||
be stopped at the moment. */
|
||||
delete_at_next_stop (&tp->control.step_resume_breakpoint);
|
||||
delete_at_next_stop (&tp->control.exception_resume_breakpoint);
|
||||
delete_at_next_stop (&tp->control.single_step_breakpoints);
|
||||
|
||||
delete_longjmp_breakpoint_at_next_stop (tp->num);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user