+/* All the meta data necessary to extract the call's return value. */
+
+struct call_return_meta_info
+{
+ /* The caller frame's architecture. */
+ struct gdbarch *gdbarch;
+
+ /* The called function. */
+ struct value *function;
+
+ /* The return value's type. */
+ struct type *value_type;
+
+ /* Are we returning a value using a structure return or a normal
+ value return? */
+ int struct_return_p;
+
+ /* If using a structure return, this is the structure's address. */
+ CORE_ADDR struct_addr;
+};
+
+/* Extract the called function's return value. */
+
+static struct value *
+get_call_return_value (struct call_return_meta_info *ri)
+{
+ struct value *retval = NULL;
+ thread_info *thr = inferior_thread ();
+ bool stack_temporaries = thread_stack_temporaries_enabled_p (thr);
+
+ if (TYPE_CODE (ri->value_type) == TYPE_CODE_VOID)
+ retval = allocate_value (ri->value_type);
+ else if (ri->struct_return_p)
+ {
+ if (stack_temporaries)
+ {
+ retval = value_from_contents_and_address (ri->value_type, NULL,
+ ri->struct_addr);
+ push_thread_stack_temporary (thr, retval);
+ }
+ else
+ {
+ retval = allocate_value (ri->value_type);
+ read_value_memory (retval, 0, 1, ri->struct_addr,
+ value_contents_raw (retval),
+ TYPE_LENGTH (ri->value_type));
+ }
+ }
+ else
+ {
+ retval = allocate_value (ri->value_type);
+ gdbarch_return_value (ri->gdbarch, ri->function, ri->value_type,
+ get_current_regcache (),
+ value_contents_raw (retval), NULL);
+ if (stack_temporaries && class_or_union_p (ri->value_type))
+ {
+ /* Values of class type returned in registers are copied onto
+ the stack and their lval_type set to lval_memory. This is
+ required because further evaluation of the expression
+ could potentially invoke methods on the return value
+ requiring GDB to evaluate the "this" pointer. To evaluate
+ the this pointer, GDB needs the memory address of the
+ value. */
+ value_force_lval (retval, ri->struct_addr);
+ push_thread_stack_temporary (thr, retval);
+ }
+ }
+
+ gdb_assert (retval != NULL);
+ return retval;
+}
+
+/* Data for the FSM that manages an infcall. It's main job is to
+ record the called function's return value. */
+
+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;
+}
+