/* Perform an inferior function call, for GDB, the GNU debugger.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "command.h"
#include "dummy-frame.h"
#include "ada-lang.h"
+#include "f-lang.h"
#include "gdbthread.h"
#include "event-top.h"
#include "observable.h"
#include "interps.h"
#include "thread-fsm.h"
#include <algorithm>
+#include "common/scope-exit.h"
/* If we can't find a function's name from its address,
we print this instead. */
}
/* Perform the standard coercions that are specified
- for arguments to be passed to C or Ada functions.
+ for arguments to be passed to C, Ada or Fortran functions.
If PARAM_TYPE is non-NULL, it is the expected parameter type.
IS_PROTOTYPED is non-zero if the function declaration is prototyped.
struct type *type
= param_type ? check_typedef (param_type) : arg_type;
- /* Perform any Ada-specific coercion first. */
+ /* Perform any Ada- and Fortran-specific coercion first. */
if (current_language->la_language == language_ada)
arg = ada_convert_actual (arg, type);
+ else if (current_language->la_language == language_fortran)
+ type = fortran_preserve_arg_pointer (arg, type);
/* Force the value to the target if we will need its address. At
this point, we could allocate arguments on the stack instead of
static CORE_ADDR
push_dummy_code (struct gdbarch *gdbarch,
CORE_ADDR sp, CORE_ADDR funaddr,
- struct value **args, int nargs,
+ gdb::array_view<value *> args,
struct type *value_type,
CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
struct regcache *regcache)
gdb_assert (gdbarch_push_dummy_code_p (gdbarch));
return gdbarch_push_dummy_code (gdbarch, sp, funaddr,
- args, nargs, value_type, real_pc, bp_addr,
+ args.data (), args.size (),
+ value_type, real_pc, bp_addr,
regcache);
}
/* 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
+struct call_thread_fsm : public thread_fsm
{
- /* The base class. */
- struct thread_fsm 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;
+ struct value *return_value = nullptr;
/* The top level that started the infcall (and is synchronously
waiting for it to end). */
struct ui *waiting_ui;
-};
-static int call_thread_fsm_should_stop (struct thread_fsm *self,
- struct thread_info *thread);
-static int call_thread_fsm_should_notify_stop (struct thread_fsm *self);
+ 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);
-/* call_thread_fsm's vtable. */
+ bool should_stop (struct thread_info *thread) override;
-static struct thread_fsm_ops call_thread_fsm_ops =
-{
- NULL, /*dtor */
- NULL, /* clean_up */
- call_thread_fsm_should_stop,
- NULL, /* return_value */
- NULL, /* async_reply_reason*/
- call_thread_fsm_should_notify_stop,
+ bool should_notify_stop () override;
};
/* Allocate a new call_thread_fsm object. */
-static struct call_thread_fsm *
-new_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)
+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)
{
- struct call_thread_fsm *sm;
-
- sm = XCNEW (struct call_thread_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &call_thread_fsm_ops, cmd_interp);
-
- sm->return_meta_info.gdbarch = gdbarch;
- sm->return_meta_info.function = function;
- sm->return_meta_info.value_type = value_type;
- sm->return_meta_info.struct_return_p = struct_return_p;
- sm->return_meta_info.struct_addr = struct_addr;
-
- sm->waiting_ui = waiting_ui;
-
- return sm;
+ 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. */
-static int
-call_thread_fsm_should_stop (struct thread_fsm *self,
- struct thread_info *thread)
+bool
+call_thread_fsm::should_stop (struct thread_info *thread)
{
- struct call_thread_fsm *f = (struct call_thread_fsm *) self;
-
if (stop_stack_dummy == STOP_STACK_DUMMY)
{
/* Done. */
- thread_fsm_set_finished (self);
+ set_finished ();
/* Stash the return value before the dummy frame is popped and
registers are restored to what they were before the
call.. */
- f->return_value = get_call_return_value (&f->return_meta_info);
+ 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, f->waiting_ui);
+ scoped_restore save_ui = make_scoped_restore (¤t_ui, waiting_ui);
target_terminal::ours ();
- f->waiting_ui->prompt_state = PROMPT_NEEDED;
+ waiting_ui->prompt_state = PROMPT_NEEDED;
}
- return 1;
+ return true;
}
/* Implementation of should_notify_stop method for infcalls. */
-static int
-call_thread_fsm_should_notify_stop (struct thread_fsm *self)
+bool
+call_thread_fsm::should_notify_stop ()
{
- if (thread_fsm_finished_p (self))
+ if (finished_p ())
{
/* Infcall succeeded. Be silent and proceed with evaluating the
expression. */
- return 0;
+ return false;
}
/* Something wrong happened. E.g., an unexpected breakpoint
triggered, or a signal was intercepted. Notify the stop. */
- return 1;
+ return true;
}
/* Subroutine of call_function_by_hand to simplify it.
run_inferior_call (struct call_thread_fsm *sm,
struct thread_info *call_thread, CORE_ADDR real_pc)
{
- struct gdb_exception caught_error = exception_none;
+ 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;
/* 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->thread_fsm;
+ 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
+ try
{
proceed (real_pc, GDB_SIGNAL_0);
target supports asynchronous execution. */
wait_sync_command_done ();
}
- CATCH (e, RETURN_MASK_ALL)
+ catch (const gdb_exception &e)
{
caught_error = e;
}
- END_CATCH
/* If GDB has the prompt blocked before, then ensure that it remains
so. normal_stop calls async_enable_stdin, so reset the prompt
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,
type *default_return_type,
- int nargs, struct value **args)
+ gdb::array_view<value *> args)
{
return call_function_by_hand_dummy (function, default_return_type,
- nargs, args, NULL, NULL);
+ args, NULL, NULL);
}
/* All this stuff with a dummy frame may seem unnecessarily complicated
struct value *
call_function_by_hand_dummy (struct value *function,
type *default_return_type,
- int nargs, struct value **args,
+ gdb::array_view<value *> args,
dummy_frame_dtor_ftype *dummy_dtor,
void *dummy_dtor_data)
{
CORE_ADDR sp;
struct type *target_values_type;
- unsigned char struct_return = 0, hidden_first_param_p = 0;
+ function_call_return_method return_method = return_method_normal;
CORE_ADDR struct_addr = 0;
CORE_ADDR real_pc;
CORE_ADDR bp_addr;
struct frame_id dummy_id;
struct frame_info *frame;
struct gdbarch *gdbarch;
- struct cleanup *terminate_bp_cleanup;
ptid_t call_thread_ptid;
struct gdb_exception e;
char name_buf[RAW_FUNCTION_ADDRESS_SIZE];
values_type = check_typedef (values_type);
- /* Are we returning a value using a structure return (passing a
- hidden argument pointing to storage) or a normal value return?
- There are two cases: language-mandated structure return and
- target ABI structure return. The variable STRUCT_RETURN only
- describes the latter. The language version is handled by passing
- the return location as the first parameter to the function,
- even preceding "this". This is different from the target
- ABI version, which is target-specific; for instance, on ia64
- the first argument is passed in out0 but the hidden structure
- return pointer would normally be passed in r8. */
+ /* Are we returning a value using a structure return? */
if (gdbarch_return_in_first_hidden_param_p (gdbarch, values_type))
{
- hidden_first_param_p = 1;
+ return_method = return_method_hidden_param;
/* Tell the target specific argument pushing routine not to
expect a value. */
}
else
{
- struct_return = using_struct_return (gdbarch, function, values_type);
+ if (using_struct_return (gdbarch, function, values_type))
+ return_method = return_method_struct;
target_values_type = values_type;
}
/* Be careful BP_ADDR is in inferior PC encoding while
BP_ADDR_AS_ADDRESS is a plain memory address. */
- sp = push_dummy_code (gdbarch, sp, funaddr, args, nargs,
+ sp = push_dummy_code (gdbarch, sp, funaddr, args,
target_values_type, &real_pc, &bp_addr,
get_current_regcache ());
internal_error (__FILE__, __LINE__, _("bad switch"));
}
- if (nargs < TYPE_NFIELDS (ftype))
+ if (args.size () < TYPE_NFIELDS (ftype))
error (_("Too few arguments in function call."));
- for (int i = nargs - 1; i >= 0; i--)
+ for (int i = args.size () - 1; i >= 0; i--)
{
int prototyped;
struct type *param_type;
-
+
/* FIXME drow/2002-05-31: Should just always mark methods as
prototyped. Can we respect TYPE_VARARGS? Probably not. */
if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
is being evaluated is OK because the thread is stopped until the
expression is completely evaluated. */
- if (struct_return || hidden_first_param_p
+ if (return_method != return_method_normal
|| (stack_temporaries && class_or_union_p (values_type)))
{
if (gdbarch_inner_than (gdbarch, 1, 2))
}
std::vector<struct value *> new_args;
- if (hidden_first_param_p)
+ if (return_method == return_method_hidden_param)
{
/* Add the new argument to the front of the argument list. */
+ new_args.reserve (args.size ());
new_args.push_back
(value_from_pointer (lookup_pointer_type (values_type), struct_addr));
- std::copy (&args[0], &args[nargs], std::back_inserter (new_args));
- args = new_args.data ();
- nargs++;
+ new_args.insert (new_args.end (), args.begin (), args.end ());
+ args = new_args;
}
/* Create the dummy stack frame. Pass in the call dummy address as,
presumably, the ABI code knows where, in the call dummy, the
return address should be pointed. */
sp = gdbarch_push_dummy_call (gdbarch, function, get_current_regcache (),
- bp_addr, nargs, args,
- sp, struct_return, struct_addr);
+ bp_addr, args.size (), args.data (),
+ sp, return_method, struct_addr);
/* Set up a frame ID for the dummy frame so we can pass it to
set_momentary_breakpoint. We need to give the breakpoint a frame
dummy_dtor, dummy_dtor_data);
/* Register a clean-up for unwind_on_terminating_exception_breakpoint. */
- terminate_bp_cleanup = make_cleanup (cleanup_delete_std_terminate_breakpoint,
- NULL);
+ SCOPE_EXIT { delete_std_terminate_breakpoint (); };
/* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP -
If you're looking to implement asynchronous dummy-frames, then
not report the stop to the user, and captures the return value
before the dummy frame is popped. run_inferior_call registers
it with the thread ASAP. */
- sm = new_call_thread_fsm (current_ui, command_interp (),
+ sm = new call_thread_fsm (current_ui, command_interp (),
gdbarch, function,
values_type,
- struct_return || hidden_first_param_p,
+ return_method != return_method_normal,
struct_addr);
e = run_inferior_call (sm, call_thread.get (), real_pc);
if (call_thread->state != THREAD_EXITED)
{
/* The FSM should still be the same. */
- gdb_assert (call_thread->thread_fsm == &sm->thread_fsm);
+ gdb_assert (call_thread->thread_fsm == sm);
- if (thread_fsm_finished_p (call_thread->thread_fsm))
+ if (call_thread->thread_fsm->finished_p ())
{
struct value *retval;
/* Clean up / destroy the call FSM, and restore the
original one. */
- thread_fsm_clean_up (call_thread->thread_fsm, call_thread.get ());
- thread_fsm_delete (call_thread->thread_fsm);
+ call_thread->thread_fsm->clean_up (call_thread.get ());
+ delete call_thread->thread_fsm;
call_thread->thread_fsm = saved_sm;
maybe_remove_breakpoints ();
- do_cleanups (terminate_bp_cleanup);
gdb_assert (retval != NULL);
return retval;
}
- /* Didn't complete. Restore previous state machine, and
- handle the error. */
+ /* Didn't complete. Clean up / destroy the call FSM, and restore the
+ previous state machine, and handle the error. */
+ call_thread->thread_fsm->clean_up (call_thread.get ());
+ delete call_thread->thread_fsm;
call_thread->thread_fsm = saved_sm;
}
}
Evaluation of the expression containing the function\n\
(%s) will be abandoned.\n\
When the function is done executing, GDB will silently stop."),
- e.message, name);
+ e.what (), name);
case RETURN_QUIT:
default:
throw_exception (e);