aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-10-15 20:18:32 +0100
committerPedro Alves <palves@redhat.com>2014-10-15 20:18:32 +0100
commit34b7e8a6ad0a735ecc0a953c8b65846d4776c88e (patch)
tree31c70923029efc37d6c4e7e305ca331164b7035e /gdb
parent5b834a0a5da717c7d1a8d539623e75f07a474e32 (diff)
downloadgdb-34b7e8a6ad0a735ecc0a953c8b65846d4776c88e.zip
gdb-34b7e8a6ad0a735ecc0a953c8b65846d4776c88e.tar.gz
gdb-34b7e8a6ad0a735ecc0a953c8b65846d4776c88e.tar.bz2
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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog51
-rw-r--r--gdb/breakpoint.c64
-rw-r--r--gdb/breakpoint.h10
-rw-r--r--gdb/gdbthread.h20
-rw-r--r--gdb/infrun.c113
-rw-r--r--gdb/record-full.c8
-rw-r--r--gdb/thread.c31
7 files changed, 174 insertions, 123 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e7108ab..a2b197c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,56 @@
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.
(delete_step_resume_breakpoint)
(delete_exception_resume_breakpoint): Use it.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index d85757b..cab6c56 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -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,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 8b833bd2..cd3e7ee 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -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 *);
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 36ad5a7..178fd4a 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -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);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 29c37e1..0f30a62 100644
--- a/gdb/infrun.c
+++ b/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);
+}
+
+/* Delete the single-step breakpoints of the threads that just
+ stopped. */
- if (single_step_breakpoints_inserted ())
- remove_single_step_breakpoints ();
+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);
diff --git a/gdb/record-full.c b/gdb/record-full.c
index abe505f..c041853 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -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;
diff --git a/gdb/thread.c b/gdb/thread.c
index 82c6760..5a1d2e3 100644
--- a/gdb/thread.c
+++ b/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);