+struct call_thread_fsm : public thread_fsm
+{
+ /* All the info necessary to be able to extract the return
+ value. */
+ struct call_return_meta_info return_meta_info;
+
+ /* The called function's return value. This is extracted from the
+ target before the dummy frame is popped. */
+ struct value *return_value = nullptr;
+
+ /* The top level that started the infcall (and is synchronously
+ waiting for it to end). */
+ struct ui *waiting_ui;
+
+ call_thread_fsm (struct ui *waiting_ui, struct interp *cmd_interp,
+ struct gdbarch *gdbarch, struct value *function,
+ struct type *value_type,
+ int struct_return_p, CORE_ADDR struct_addr);
+
+ bool should_stop (struct thread_info *thread) override;
+
+ bool should_notify_stop () override;
+};
+
+/* Allocate a new call_thread_fsm object. */
+
+call_thread_fsm::call_thread_fsm (struct ui *waiting_ui,
+ struct interp *cmd_interp,
+ struct gdbarch *gdbarch,
+ struct value *function,
+ struct type *value_type,
+ int struct_return_p, CORE_ADDR struct_addr)
+ : thread_fsm (cmd_interp),
+ waiting_ui (waiting_ui)
+{
+ return_meta_info.gdbarch = gdbarch;
+ return_meta_info.function = function;
+ return_meta_info.value_type = value_type;
+ return_meta_info.struct_return_p = struct_return_p;
+ return_meta_info.struct_addr = struct_addr;
+}
+
+/* Implementation of should_stop method for infcalls. */
+
+bool
+call_thread_fsm::should_stop (struct thread_info *thread)
+{
+ if (stop_stack_dummy == STOP_STACK_DUMMY)
+ {
+ /* Done. */
+ set_finished ();
+
+ /* Stash the return value before the dummy frame is popped and
+ registers are restored to what they were before the
+ call.. */
+ return_value = get_call_return_value (&return_meta_info);
+
+ /* Break out of wait_sync_command_done. */
+ scoped_restore save_ui = make_scoped_restore (¤t_ui, waiting_ui);
+ target_terminal::ours ();
+ waiting_ui->prompt_state = PROMPT_NEEDED;
+ }
+
+ return true;
+}
+
+/* Implementation of should_notify_stop method for infcalls. */
+
+bool
+call_thread_fsm::should_notify_stop ()
+{
+ if (finished_p ())
+ {
+ /* Infcall succeeded. Be silent and proceed with evaluating the
+ expression. */
+ return false;
+ }
+
+ /* Something wrong happened. E.g., an unexpected breakpoint
+ triggered, or a signal was intercepted. Notify the stop. */
+ return true;
+}
+
+/* Subroutine of call_function_by_hand to simplify it.
+ Start up the inferior and wait for it to stop.
+ Return the exception if there's an error, or an exception with
+ reason >= 0 if there's no error.
+
+ This is done inside a TRY_CATCH so the caller needn't worry about
+ thrown errors. The caller should rethrow if there's an error. */
+
+static struct gdb_exception
+run_inferior_call (struct call_thread_fsm *sm,
+ struct thread_info *call_thread, CORE_ADDR real_pc)
+{
+ struct gdb_exception caught_error;
+ int saved_in_infcall = call_thread->control.in_infcall;
+ ptid_t call_thread_ptid = call_thread->ptid;
+ enum prompt_state saved_prompt_state = current_ui->prompt_state;
+ int was_running = call_thread->state == THREAD_RUNNING;
+ int saved_ui_async = current_ui->async;
+
+ /* Infcalls run synchronously, in the foreground. */
+ current_ui->prompt_state = PROMPT_BLOCKED;
+ /* So that we don't print the prompt prematurely in
+ fetch_inferior_event. */
+ current_ui->async = 0;
+
+ delete_file_handler (current_ui->input_fd);
+
+ call_thread->control.in_infcall = 1;
+
+ clear_proceed_status (0);
+
+ /* Associate the FSM with the thread after clear_proceed_status
+ (otherwise it'd clear this FSM), and before anything throws, so
+ we don't leak it (and any resources it manages). */
+ call_thread->thread_fsm = sm;
+
+ disable_watchpoints_before_interactive_call_start ();
+
+ /* We want to print return value, please... */
+ call_thread->control.proceed_to_finish = 1;
+
+ try
+ {
+ proceed (real_pc, GDB_SIGNAL_0);
+
+ /* Inferior function calls are always synchronous, even if the
+ target supports asynchronous execution. */
+ wait_sync_command_done ();
+ }
+ catch (gdb_exception &e)
+ {
+ caught_error = std::move (e);
+ }
+
+ /* If GDB has the prompt blocked before, then ensure that it remains
+ so. normal_stop calls async_enable_stdin, so reset the prompt
+ state again here. In other cases, stdin will be re-enabled by
+ inferior_event_handler, when an exception is thrown. */
+ current_ui->prompt_state = saved_prompt_state;
+ if (current_ui->prompt_state == PROMPT_BLOCKED)
+ delete_file_handler (current_ui->input_fd);
+ else
+ ui_register_input_event_handler (current_ui);
+ current_ui->async = saved_ui_async;
+
+ /* If the infcall does NOT succeed, normal_stop will have already
+ finished the thread states. However, on success, normal_stop
+ defers here, so that we can set back the thread states to what
+ they were before the call. Note that we must also finish the
+ state of new threads that might have spawned while the call was
+ running. The main cases to handle are:
+
+ - "(gdb) print foo ()", or any other command that evaluates an
+ expression at the prompt. (The thread was marked stopped before.)
+
+ - "(gdb) break foo if return_false()" or similar cases where we
+ do an infcall while handling an event (while the thread is still
+ marked running). In this example, whether the condition
+ evaluates true and thus we'll present a user-visible stop is
+ decided elsewhere. */
+ if (!was_running
+ && call_thread_ptid == inferior_ptid
+ && stop_stack_dummy == STOP_STACK_DUMMY)
+ finish_thread_state (user_visible_resume_ptid (0));
+
+ enable_watchpoints_after_interactive_call_stop ();
+
+ /* Call breakpoint_auto_delete on the current contents of the bpstat
+ of inferior call thread.
+ If all error()s out of proceed ended up calling normal_stop
+ (and perhaps they should; it already does in the special case
+ of error out of resume()), then we wouldn't need this. */
+ if (caught_error.reason < 0)
+ {
+ if (call_thread->state != THREAD_EXITED)
+ breakpoint_auto_delete (call_thread->control.stop_bpstat);
+ }
+
+ call_thread->control.in_infcall = saved_in_infcall;
+
+ return caught_error;
+}
+
+/* See infcall.h. */
+
+struct value *
+call_function_by_hand (struct value *function,
+ type *default_return_type,
+ gdb::array_view<value *> args)