/* Perform an inferior function call, for GDB, the GNU debugger.
- Copyright (C) 1986-2020 Free Software Foundation, Inc.
+ Copyright (C) 1986-2022 Free Software Foundation, Inc.
This file is part of GDB.
we print this instead. */
#define RAW_FUNCTION_ADDRESS_FORMAT "at 0x%s"
#define RAW_FUNCTION_ADDRESS_SIZE (sizeof (RAW_FUNCTION_ADDRESS_FORMAT) \
- + 2 * sizeof (CORE_ADDR))
+ + 2 * sizeof (CORE_ADDR))
/* NOTE: cagney/2003-04-16: What's the future of this code?
saved by the called function. */
arg = value_coerce_to_target (arg);
- switch (TYPE_CODE (type))
+ switch (type->code ())
{
case TYPE_CODE_REF:
case TYPE_CODE_RVALUE_REF:
if the value was not previously in memory - in some cases
we should clearly be allowing this, but how? */
new_value = value_cast (TYPE_TARGET_TYPE (type), arg);
- new_value = value_ref (new_value, TYPE_CODE (type));
+ new_value = value_ref (new_value, type->code ());
return new_value;
}
case TYPE_CODE_INT:
type = builtin->builtin_int;
}
/* Currently all target ABIs require at least the width of an integer
- type for an argument. We may have to conditionalize the following
- type coercion for future targets. */
+ type for an argument. We may have to conditionalize the following
+ type coercion for future targets. */
if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin->builtin_int))
type = builtin->builtin_int;
break;
break;
case TYPE_CODE_ARRAY:
/* Arrays are coerced to pointers to their first element, unless
- they are vectors, in which case we want to leave them alone,
- because they are passed by value. */
- if (current_language->c_style_arrays)
- if (!TYPE_VECTOR (type))
+ they are vectors, in which case we want to leave them alone,
+ because they are passed by value. */
+ if (current_language->c_style_arrays_p ())
+ if (!type->is_vector ())
type = lookup_pointer_type (TYPE_TARGET_TYPE (type));
break;
case TYPE_CODE_UNDEF:
struct type **function_type)
{
struct type *ftype = check_typedef (value_type (function));
- struct gdbarch *gdbarch = get_type_arch (ftype);
+ struct gdbarch *gdbarch = ftype->arch ();
struct type *value_type = NULL;
/* Initialize it just to avoid a GCC false warning. */
CORE_ADDR funaddr = 0;
part of it. */
/* Determine address to call. */
- if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
- || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ if (ftype->code () == TYPE_CODE_FUNC
+ || ftype->code () == TYPE_CODE_METHOD)
funaddr = value_address (function);
- else if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
+ else if (ftype->code () == TYPE_CODE_PTR)
{
funaddr = value_as_address (function);
ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
- if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
- || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
- funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
- current_top_target ());
+ if (ftype->code () == TYPE_CODE_FUNC
+ || ftype->code () == TYPE_CODE_METHOD)
+ funaddr = gdbarch_convert_from_func_ptr_addr
+ (gdbarch, funaddr, current_inferior ()->top_target());
}
- if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
- || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ if (ftype->code () == TYPE_CODE_FUNC
+ || ftype->code () == TYPE_CODE_METHOD)
{
- if (TYPE_GNU_IFUNC (ftype))
+ if (ftype->is_gnu_ifunc ())
{
CORE_ADDR resolver_addr = funaddr;
else
value_type = TYPE_TARGET_TYPE (ftype);
}
- else if (TYPE_CODE (ftype) == TYPE_CODE_INT)
+ else if (ftype->code () == TYPE_CODE_INT)
{
/* Handle the case of functions lacking debugging info.
- Their values are characters since their addresses are char. */
+ Their values are characters since their addresses are char. */
if (TYPE_LENGTH (ftype) == 1)
funaddr = value_as_address (value_addr (function));
else
funaddr = value_as_address (value_addr (function));
nfunaddr = funaddr;
- funaddr
- = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
- current_top_target ());
+ funaddr = gdbarch_convert_from_func_ptr_addr
+ (gdbarch, funaddr, current_inferior ()->top_target ());
if (funaddr != nfunaddr)
found_descriptor = 1;
}
thread_info *thr = inferior_thread ();
bool stack_temporaries = thread_stack_temporaries_enabled_p (thr);
- if (TYPE_CODE (ri->value_type) == TYPE_CODE_VOID)
+ if (ri->value_type->code () == TYPE_CODE_VOID)
retval = allocate_value (ri->value_type);
else if (ri->struct_return_p)
{
{
retval = allocate_value (ri->value_type);
read_value_memory (retval, 0, 1, ri->struct_addr,
- value_contents_raw (retval),
+ value_contents_raw (retval).data (),
TYPE_LENGTH (ri->value_type));
}
}
retval = allocate_value (ri->value_type);
gdbarch_return_value (ri->gdbarch, ri->function, ri->value_type,
get_current_regcache (),
- value_contents_raw (retval), NULL);
+ value_contents_raw (retval).data (), NULL);
if (stack_temporaries && class_or_union_p (ri->value_type))
{
/* Values of class type returned in registers are copied onto
thrown errors. The caller should rethrow if there's an error. */
static struct gdb_exception
-run_inferior_call (struct call_thread_fsm *sm,
+run_inferior_call (std::unique_ptr<call_thread_fsm> sm,
struct thread_info *call_thread, CORE_ADDR real_pc)
{
struct gdb_exception caught_error;
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;
+ (otherwise it'd clear this FSM). */
+ call_thread->set_thread_fsm (std::move (sm));
disable_watchpoints_before_interactive_call_start ();
error (_("Cannot call functions in the program: "
"may-call-functions is off."));
- if (!target_has_execution)
+ if (!target_has_execution ())
noprocess ();
if (get_traceframe_number () >= 0)
type *values_type;
CORE_ADDR funaddr = find_function_addr (function, &values_type, &ftype);
+ if (is_nocall_function (ftype))
+ error (_("Cannot call the function '%s' which does not follow the "
+ "target calling convention."),
+ get_function_name (funaddr, name_buf, sizeof (name_buf)));
+
if (values_type == NULL)
values_type = default_return_type;
if (values_type == NULL)
values_type = check_typedef (values_type);
- if (args.size () < TYPE_NFIELDS (ftype))
+ if (args.size () < ftype->num_fields ())
error (_("Too few arguments in function call."));
/* A holder for the inferior status.
do is add FRAME_ALIGN() to the architecture vector. If that
fails, try dummy_id().
- If the ABI specifies a "Red Zone" (see the doco) the code
- below will quietly trash it. */
+ If the ABI specifies a "Red Zone" (see the doco) the code
+ below will quietly trash it. */
sp = old_sp;
/* Skip over the stack temporaries that might have been generated during
struct value *lastval;
lastval = get_last_thread_stack_temporary (call_thread.get ());
- if (lastval != NULL)
+ if (lastval != NULL)
{
CORE_ADDR lastval_addr = value_address (lastval);
/* 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)
+ if (ftype->code () == TYPE_CODE_METHOD)
prototyped = 1;
- if (TYPE_TARGET_TYPE (ftype) == NULL && TYPE_NFIELDS (ftype) == 0
- && default_return_type != NULL)
+ else if (TYPE_TARGET_TYPE (ftype) == NULL && ftype->num_fields () == 0
+ && default_return_type != NULL)
{
/* Calling a no-debug function with the return type
explicitly cast. Assume the function is prototyped,
*/
prototyped = 1;
}
- else if (i < TYPE_NFIELDS (ftype))
- prototyped = TYPE_PROTOTYPED (ftype);
+ else if (i < ftype->num_fields ())
+ prototyped = ftype->is_prototyped ();
else
prototyped = 0;
- if (i < TYPE_NFIELDS (ftype))
- param_type = TYPE_FIELD_TYPE (ftype, i);
+ if (i < ftype->num_fields ())
+ param_type = ftype->field (i).type ();
else
param_type = NULL;
auto info = language_pass_by_reference (param_type);
if (!info.copy_constructible)
error (_("expression cannot be evaluated because the type '%s' "
- "is not copy constructible"), TYPE_NAME (param_type));
+ "is not copy constructible"), param_type->name ());
if (!info.destructible)
error (_("expression cannot be evaluated because the type '%s' "
- "is not destructible"), TYPE_NAME (param_type));
+ "is not destructible"), param_type->name ());
if (info.trivially_copyable)
continue;
if (info.trivially_copy_constructible)
{
int length = TYPE_LENGTH (param_type);
- write_memory (addr, value_contents (args[i]), length);
+ write_memory (addr, value_contents (args[i]).data (), length);
}
else
{
value *copy_ctor;
value *cctor_args[2] = { clone_ptr, original_arg };
find_overload_match (gdb::make_array_view (cctor_args, 2),
- TYPE_NAME (param_type), METHOD,
+ param_type->name (), METHOD,
&clone_ptr, nullptr, ©_ctor, nullptr,
nullptr, 0, EVAL_NORMAL);
if (copy_ctor == nullptr)
error (_("expression cannot be evaluated because a copy "
"constructor for the type '%s' could not be found "
- "(maybe inlined?)"), TYPE_NAME (param_type));
+ "(maybe inlined?)"), param_type->name ());
call_function_by_hand (copy_ctor, default_return_type,
gdb::make_array_view (cctor_args, 2));
if (dtor_name == nullptr)
error (_("expression cannot be evaluated because a destructor "
"for the type '%s' could not be found "
- "(maybe inlined?)"), TYPE_NAME (param_type));
+ "(maybe inlined?)"), param_type->name ());
value *dtor
= find_function_in_inferior (dtor_name, 0);
just below is the place to chop this function in two.. */
{
- struct thread_fsm *saved_sm;
- struct call_thread_fsm *sm;
-
/* Save the current FSM. We'll override it. */
- saved_sm = call_thread->thread_fsm;
- call_thread->thread_fsm = NULL;
+ std::unique_ptr<thread_fsm> saved_sm = call_thread->release_thread_fsm ();
+ struct call_thread_fsm *sm;
/* Save this thread's ptid, we need it later but the thread
may have exited. */
values_type,
return_method != return_method_normal,
struct_addr);
-
- e = run_inferior_call (sm, call_thread.get (), real_pc);
+ {
+ std::unique_ptr<call_thread_fsm> sm_up (sm);
+ e = run_inferior_call (std::move (sm_up), call_thread.get (), real_pc);
+ }
gdb::observers::inferior_call_post.notify (call_thread_ptid, funaddr);
if (call_thread->state != THREAD_EXITED)
{
/* The FSM should still be the same. */
- gdb_assert (call_thread->thread_fsm == sm);
+ gdb_assert (call_thread->thread_fsm () == sm);
- if (call_thread->thread_fsm->finished_p ())
+ if (call_thread->thread_fsm ()->finished_p ())
{
struct value *retval;
/* Get the return value. */
retval = sm->return_value;
- /* Clean up / destroy the call FSM, and restore the
- original one. */
- call_thread->thread_fsm->clean_up (call_thread.get ());
- delete call_thread->thread_fsm;
- call_thread->thread_fsm = saved_sm;
+ /* Restore the original FSM and clean up / destroh the call FSM.
+ Doing it in this order ensures that if the call to clean_up
+ throws, the original FSM is properly restored. */
+ {
+ std::unique_ptr<thread_fsm> finalizing
+ = call_thread->release_thread_fsm ();
+ call_thread->set_thread_fsm (std::move (saved_sm));
+
+ finalizing->clean_up (call_thread.get ());
+ }
maybe_remove_breakpoints ();
/* 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;
+ {
+ std::unique_ptr<thread_fsm> finalizing
+ = call_thread->release_thread_fsm ();
+ call_thread->set_thread_fsm (std::move (saved_sm));
+
+ finalizing->clean_up (call_thread.get ());
+ }
}
}
if (e.reason < 0)
{
const char *name = get_function_name (funaddr,
- name_buf, sizeof (name_buf));
+ name_buf, sizeof (name_buf));
discard_infcall_control_state (inf_status.release ());
/* We could discard the dummy frame here if the program exited,
- but it will get garbage collected the next time the program is
- run anyway. */
+ but it will get garbage collected the next time the program is
+ run anyway. */
switch (e.reason)
{
/* If the program has exited, or we stopped at a different thread,
exit and inform the user. */
- if (! target_has_execution)
+ if (! target_has_execution ())
{
const char *name = get_function_name (funaddr,
name_buf, sizeof (name_buf));
discard_infcall_control_state (inf_status.release ());
/* We could discard the dummy frame here given that the program exited,
- but it will get garbage collected the next time the program is
- run anyway. */
+ but it will get garbage collected the next time the program is
+ run anyway. */
error (_("The program being debugged exited while in a function "
"called from GDB.\n"
gdb_assert_not_reached ("... should not be here");
}
+void _initialize_infcall ();
void
-_initialize_infcall (void)
+_initialize_infcall ()
{
add_setshow_boolean_cmd ("may-call-functions", no_class,
&may_call_functions_p, _("\