/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2019 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
Can not resume the parent process over vfork in the foreground while\n\
holding the child stopped. Try \"set detach-on-fork\" or \
\"set schedule-multiple\".\n"));
- /* FIXME output string > 80 columns. */
return 1;
}
{
for (thread_info *tp : all_non_exited_threads (resume_ptid))
{
+ switch_to_thread_no_regs (tp);
+
/* Ignore the current thread here. It's handled
afterwards. */
if (tp == cur_thr)
thread_step_over_chain_enqueue (tp);
}
+
+ switch_to_thread (cur_thr);
}
/* Enqueue the current thread last, so that we move all other
Start all other threads that are implicitly resumed too. */
for (thread_info *tp : all_non_exited_threads (resume_ptid))
{
+ switch_to_thread_no_regs (tp);
+
if (tp->resumed)
{
if (debug_infrun)
finish_state.release ();
+ /* If we've switched threads above, switch back to the previously
+ current thread. We don't want the user to see a different
+ selected thread. */
+ switch_to_thread (cur_thr);
+
/* Tell the event loop to wait for it to stop. If the target
supports asynchronous execution, it'll do this from within
target_resume. */
set_current_traceframe (-1);
}
- gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
-
- if (non_stop)
- /* In non-stop mode, the user/frontend should not notice a thread
- switch due to internal events. Make sure we reverse to the
- user selected thread and frame after handling the event and
- running any breakpoint commands. */
- maybe_restore_thread.emplace ();
+ /* The user/frontend should not notice a thread switch due to
+ internal events. Make sure we revert to the user selected
+ thread and frame after handling the event and running any
+ breakpoint commands. */
+ scoped_restore_current_thread restore_thread;
overlay_cache_invalid = 1;
/* Flush target cache before starting to handle each event. Target
inferior_event_handler (INF_EXEC_COMPLETE, NULL);
cmd_done = 1;
}
+
+ /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
+ previously selected thread is gone. We have two
+ choices - switch to no thread selected, or restore the
+ previously selected thread (now exited). We chose the
+ later, just because that's what GDB used to do. After
+ this, "info threads" says "The current thread <Thread
+ ID 2> has terminated." instead of "No thread
+ selected.". */
+ if (!non_stop
+ && cmd_done
+ && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
+ restore_thread.dont_restore ();
}
}
return 0;
}
+/* Look for an inline frame that is marked for skip.
+ If PREV_FRAME is TRUE start at the previous frame,
+ otherwise start at the current frame. Stop at the
+ first non-inline frame, or at the frame where the
+ step started. */
+
+static bool
+inline_frame_is_marked_for_skip (bool prev_frame, struct thread_info *tp)
+{
+ struct frame_info *frame = get_current_frame ();
+
+ if (prev_frame)
+ frame = get_prev_frame (frame);
+
+ for (; frame != NULL; frame = get_prev_frame (frame))
+ {
+ const char *fn = NULL;
+ symtab_and_line sal;
+ struct symbol *sym;
+
+ if (frame_id_eq (get_frame_id (frame), tp->control.step_frame_id))
+ break;
+ if (get_frame_type (frame) != INLINE_FRAME)
+ break;
+
+ sal = find_frame_sal (frame);
+ sym = get_frame_function (frame);
+
+ if (sym != NULL)
+ fn = sym->print_name ();
+
+ if (sal.line != 0
+ && function_name_is_marked_for_skip (fn, sal))
+ return true;
+ }
+
+ return false;
+}
+
/* If the event thread has the stop requested flag set, pretend it
stopped for a GDB_SIGNAL_0 (i.e., as if it stopped due to
target_stop). */
"infrun: %s executing, "
"need stop\n",
target_pid_to_str (t->ptid).c_str ());
+ switch_to_thread_no_regs (t);
target_stop (t->ptid);
t->stop_requested = 1;
}
for (thread_info *tp : all_non_exited_threads ())
{
+ switch_to_thread_no_regs (tp);
+
if (tp == event_thread)
{
if (debug_infrun)
{
struct regcache *regcache = get_thread_regcache (ecs->event_thread);
struct gdbarch *reg_gdbarch = regcache->arch ();
- scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
- inferior_ptid = ecs->ptid;
+ switch_to_thread (ecs->event_thread);
fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = %s\n",
paddress (reg_gdbarch,
tmp_sal = find_pc_line (ecs->stop_func_start, 0);
if (tmp_sal.line != 0
&& !function_name_is_marked_for_skip (ecs->stop_func_name,
- tmp_sal))
+ tmp_sal)
+ && !inline_frame_is_marked_for_skip (true, ecs->event_thread))
{
if (execution_direction == EXEC_REVERSE)
handle_step_into_function_backward (gdbarch, ecs);
if (call_sal.line == ecs->event_thread->current_line
&& call_sal.symtab == ecs->event_thread->current_symtab)
- step_into_inline_frame (ecs->event_thread);
+ {
+ step_into_inline_frame (ecs->event_thread);
+ if (inline_frame_is_marked_for_skip (false, ecs->event_thread))
+ {
+ keep_going (ecs);
+ return;
+ }
+ }
end_stepping_range (ecs);
return;
fprintf_unfiltered (gdb_stdlog,
"infrun: stepping through inlined function\n");
- if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL)
+ if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
+ || inline_frame_is_marked_for_skip (false, ecs->event_thread))
keep_going (ecs);
else
end_stepping_range (ecs);
for (thread_info *tp : all_non_exited_threads ())
{
+ switch_to_thread_no_regs (tp);
+
/* Ignore threads of processes the caller is not
resuming. */
if (!sched_multi
return 1;
}
}
+
+ switch_to_thread (ecs->event_thread);
}
return 0;