+/* Fetch the name of the function at FUNADDR.
+ This is used in printing an error message for call_function_by_hand.
+ BUF is used to print FUNADDR in hex if the function name cannot be
+ determined. It must be large enough to hold formatted result of
+ RAW_FUNCTION_ADDRESS_FORMAT. */
+
+static const char *
+get_function_name (CORE_ADDR funaddr, char *buf, int buf_size)
+{
+ {
+ struct symbol *symbol = find_pc_function (funaddr);
+
+ if (symbol)
+ return SYMBOL_PRINT_NAME (symbol);
+ }
+
+ {
+ /* Try the minimal symbols. */
+ struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (funaddr);
+
+ if (msymbol.minsym)
+ return MSYMBOL_PRINT_NAME (msymbol.minsym);
+ }
+
+ {
+ char *tmp = xstrprintf (_(RAW_FUNCTION_ADDRESS_FORMAT),
+ hex_string (funaddr));
+
+ gdb_assert (strlen (tmp) + 1 <= buf_size);
+ strcpy (buf, tmp);
+ xfree (tmp);
+ return buf;
+ }
+}
+
+/* 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 thread_info *call_thread, CORE_ADDR real_pc)
+{
+ struct gdb_exception caught_error = exception_none;
+ int saved_in_infcall = call_thread->control.in_infcall;
+ ptid_t call_thread_ptid = call_thread->ptid;
+ int saved_sync_execution = sync_execution;
+
+ /* Infcalls run synchronously, in the foreground. */
+ if (target_can_async_p ())
+ sync_execution = 1;
+
+ call_thread->control.in_infcall = 1;
+
+ clear_proceed_status (0);
+
+ disable_watchpoints_before_interactive_call_start ();
+
+ /* We want stop_registers, please... */
+ call_thread->control.proceed_to_finish = 1;
+
+ TRY
+ {
+ int was_sync = sync_execution;
+
+ proceed (real_pc, GDB_SIGNAL_0);
+
+ /* Inferior function calls are always synchronous, even if the
+ target supports asynchronous execution. Do here what
+ `proceed' itself does in sync mode. */
+ if (target_can_async_p ())
+ {
+ wait_for_inferior ();
+ normal_stop ();
+ /* If GDB was previously in sync execution mode, then ensure
+ that it remains so. normal_stop calls
+ async_enable_stdin, so reset it again here. In other
+ cases, stdin will be re-enabled by
+ inferior_event_handler, when an exception is thrown. */
+ if (was_sync)
+ async_disable_stdin ();
+ }
+ }
+ CATCH (e, RETURN_MASK_ALL)
+ {
+ caught_error = e;
+ }
+ END_CATCH
+
+ /* At this point the current thread may have changed. Refresh
+ CALL_THREAD as it could be invalid if its thread has exited. */
+ call_thread = find_thread_ptid (call_thread_ptid);
+
+ 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 != NULL)
+ breakpoint_auto_delete (call_thread->control.stop_bpstat);
+ }
+
+ if (call_thread != NULL)
+ call_thread->control.in_infcall = saved_in_infcall;
+
+ sync_execution = saved_sync_execution;
+
+ return caught_error;
+}
+
+/* A cleanup function that calls delete_std_terminate_breakpoint. */
+static void
+cleanup_delete_std_terminate_breakpoint (void *ignore)
+{
+ delete_std_terminate_breakpoint ();
+}
+
+/* See infcall.h. */
+
+struct value *
+call_function_by_hand (struct value *function, int nargs, struct value **args)
+{
+ return call_function_by_hand_dummy (function, nargs, args, NULL, NULL);
+}
+
+/* Data for dummy_frame_context_saver. Structure can be freed only
+ after both dummy_frame_context_saver_dtor and
+ dummy_frame_context_saver_drop have been called for it. */
+
+struct dummy_frame_context_saver
+{
+ /* Inferior registers fetched before associated dummy_frame got freed
+ and before any other destructors of associated dummy_frame got called.
+ It is initialized to NULL. */
+ struct regcache *retbuf;
+
+ /* It is 1 if this dummy_frame_context_saver_drop has been already
+ called. */
+ int drop_done;
+};
+
+/* Free struct dummy_frame_context_saver. */
+
+static void
+dummy_frame_context_saver_free (struct dummy_frame_context_saver *saver)
+{
+ regcache_xfree (saver->retbuf);
+ xfree (saver);
+}
+
+/* Destructor for associated dummy_frame. */
+
+static void
+dummy_frame_context_saver_dtor (void *data_voidp, int registers_valid)
+{
+ struct dummy_frame_context_saver *data = data_voidp;
+
+ gdb_assert (data->retbuf == NULL);
+
+ if (data->drop_done)
+ dummy_frame_context_saver_free (data);
+ else if (registers_valid)
+ data->retbuf = regcache_dup (get_current_regcache ());
+}
+
+/* Caller is no longer interested in this
+ struct dummy_frame_context_saver. After its associated dummy_frame
+ gets freed struct dummy_frame_context_saver can be also freed. */
+
+void
+dummy_frame_context_saver_drop (struct dummy_frame_context_saver *saver)
+{
+ saver->drop_done = 1;
+
+ if (!find_dummy_frame_dtor (dummy_frame_context_saver_dtor, saver))
+ dummy_frame_context_saver_free (saver);
+}
+
+/* Stub dummy_frame_context_saver_drop compatible with make_cleanup. */
+
+void
+dummy_frame_context_saver_cleanup (void *data)
+{
+ struct dummy_frame_context_saver *saver = data;
+
+ dummy_frame_context_saver_drop (saver);
+}
+
+/* Fetch RETBUF field of possibly opaque DTOR_DATA.
+ RETBUF must not be NULL. */
+
+struct regcache *
+dummy_frame_context_saver_get_regs (struct dummy_frame_context_saver *saver)
+{
+ gdb_assert (saver->retbuf != NULL);
+ return saver->retbuf;
+}
+
+/* Register provider of inferior registers at the time DUMMY_ID frame of
+ PTID gets freed (before inferior registers get restored to those
+ before dummy_frame). */
+
+struct dummy_frame_context_saver *
+dummy_frame_context_saver_setup (struct frame_id dummy_id, ptid_t ptid)
+{
+ struct dummy_frame_context_saver *saver;
+
+ saver = xmalloc (sizeof (*saver));
+ saver->retbuf = NULL;
+ saver->drop_done = 0;
+ register_dummy_frame_dtor (dummy_id, inferior_ptid,
+ dummy_frame_context_saver_dtor, saver);
+ return saver;
+}
+