diff options
author | Pedro Alves <palves@redhat.com> | 2014-10-15 20:18:32 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2014-10-15 20:18:32 +0100 |
commit | 34b7e8a6ad0a735ecc0a953c8b65846d4776c88e (patch) | |
tree | 31c70923029efc37d6c4e7e305ca331164b7035e /gdb/infrun.c | |
parent | 5b834a0a5da717c7d1a8d539623e75f07a474e32 (diff) | |
download | gdb-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/infrun.c')
-rw-r--r-- | gdb/infrun.c | 113 |
1 files changed, 45 insertions, 68 deletions
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); |