#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 "gdbsupport/scope-exit.h"
/* If we can't find a function's name from its address,
we print this instead. */
asynchronous inferior function call implementation, and that in
turn means restructuring the code so that it is event driven. */
+static bool may_call_functions_p = true;
+static void
+show_may_call_functions_p (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file,
+ _("Permission to call functions in the program is %s.\n"),
+ value);
+}
+
/* How you should pass arguments to a function depends on whether it
was defined in K&R style or prototype style. If you define a
function using the K&R syntax that takes a `float' argument, then
trust the debug information; the user can override this behavior
with "set coerce-float-to-double 0". */
-static int coerce_float_to_double_p = 1;
+static bool coerce_float_to_double_p = true;
static void
show_coerce_float_to_double_p (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
The default is to stop in the frame where the signal was received. */
-static int unwind_on_signal_p = 0;
+static bool unwind_on_signal_p = false;
static void
show_unwind_on_signal_p (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
The default is to unwind the frame if a std::terminate call is
made. */
-static int unwind_on_terminating_exception_p = 1;
+static bool unwind_on_terminating_exception_p = true;
static void
show_unwind_on_terminating_exception_p (struct ui_file *file, int from_tty,
}
/* 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.
- SP is the stack pointer were additional data can be pushed (updating
- its value as needed). */
+ IS_PROTOTYPED is non-zero if the function declaration is prototyped. */
static struct value *
value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
- struct type *param_type, int is_prototyped, CORE_ADDR *sp)
+ struct type *param_type, int is_prototyped)
{
const struct builtin_type *builtin = builtin_type (gdbarch);
struct type *arg_type = check_typedef (value_type (arg));
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
struct symbol *symbol = find_pc_function (funaddr);
if (symbol)
- return SYMBOL_PRINT_NAME (symbol);
+ return symbol->print_name ();
}
{
struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (funaddr);
if (msymbol.minsym)
- return MSYMBOL_PRINT_NAME (msymbol.minsym);
+ return msymbol.minsym->print_name ();
}
{
/* 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 (gdb_exception &e)
{
- caught_error = e;
+ caught_error = std::move (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)
+/* Reserve space on the stack for a value of the given type.
+ Return the address of the allocated space.
+ Make certain that the value is correctly aligned.
+ The SP argument is modified. */
+
+static CORE_ADDR
+reserve_stack_space (const type *values_type, CORE_ADDR &sp)
{
- delete_std_terminate_breakpoint ();
+ struct frame_info *frame = get_current_frame ();
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR addr = 0;
+
+ if (gdbarch_inner_than (gdbarch, 1, 2))
+ {
+ /* Stack grows downward. Align STRUCT_ADDR and SP after
+ making space. */
+ sp -= TYPE_LENGTH (values_type);
+ if (gdbarch_frame_align_p (gdbarch))
+ sp = gdbarch_frame_align (gdbarch, sp);
+ addr = sp;
+ }
+ else
+ {
+ /* Stack grows upward. Align the frame, allocate space, and
+ then again, re-align the frame??? */
+ if (gdbarch_frame_align_p (gdbarch))
+ sp = gdbarch_frame_align (gdbarch, sp);
+ addr = sp;
+ sp += TYPE_LENGTH (values_type);
+ if (gdbarch_frame_align_p (gdbarch))
+ sp = gdbarch_frame_align (gdbarch, sp);
+ }
+
+ return addr;
}
/* See infcall.h. */
making dummy frames be different from normal frames, consider that. */
/* Perform a function call in the inferior.
- ARGS is a vector of values of arguments (NARGS of them).
+ ARGS is a vector of values of arguments.
FUNCTION is a value, the function to be called.
Returns a value representing what the function returned.
May fail to return, if a breakpoint or signal is hit
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];
+ if (!may_call_functions_p)
+ error (_("Cannot call functions in the program: "
+ "may-call-functions is off."));
+
if (!target_has_execution)
noprocess ();
if (!gdbarch_push_dummy_call_p (gdbarch))
error (_("This target does not support function calls."));
+ /* Find the function type and do a sanity check. */
+ type *ftype;
+ type *values_type;
+ CORE_ADDR funaddr = find_function_addr (function, &values_type, &ftype);
+
+ if (values_type == NULL)
+ values_type = default_return_type;
+ if (values_type == NULL)
+ {
+ const char *name = get_function_name (funaddr,
+ name_buf, sizeof (name_buf));
+ error (_("'%s' has unknown return type; "
+ "cast the call to its declared return type"),
+ name);
+ }
+
+ values_type = check_typedef (values_type);
+
+ if (args.size () < TYPE_NFIELDS (ftype))
+ error (_("Too few arguments in function call."));
+
/* A holder for the inferior status.
This is only needed while we're preparing the inferior function call. */
infcall_control_state_up inf_status (save_infcall_control_state ());
void parameterless generic dummy frame calls to frameless
functions will create a sequence of effectively identical
frames (SP, FP and TOS and PC the same). This, not
- suprisingly, results in what appears to be a stack in an
+ surprisingly, results in what appears to be a stack in an
infinite loop --- when GDB tries to find a generic dummy
frame on the internal dummy frame stack, it will always
find the first one.
}
}
- type *ftype;
- type *values_type;
- CORE_ADDR funaddr = find_function_addr (function, &values_type, &ftype);
-
- if (values_type == NULL)
- values_type = default_return_type;
- if (values_type == NULL)
- {
- const char *name = get_function_name (funaddr,
- name_buf, sizeof (name_buf));
- error (_("'%s' has unknown return type; "
- "cast the call to its declared return type"),
- name);
- }
-
- values_type = check_typedef (values_type);
-
/* Are we returning a value using a structure return? */
if (gdbarch_return_in_first_hidden_param_p (gdbarch, values_type))
internal_error (__FILE__, __LINE__, _("bad switch"));
}
- if (args.size () < TYPE_NFIELDS (ftype))
- error (_("Too few arguments in function call."));
-
for (int i = args.size () - 1; i >= 0; i--)
{
int prototyped;
param_type = NULL;
args[i] = value_arg_coerce (gdbarch, args[i],
- param_type, prototyped, &sp);
+ param_type, prototyped);
if (param_type != NULL && language_pass_by_reference (param_type))
args[i] = value_addr (args[i]);
}
/* Reserve space for the return structure to be written on the
- stack, if necessary. Make certain that the value is correctly
- aligned.
+ stack, if necessary.
While evaluating expressions, we reserve space on the stack for
return values of class type even if the language ABI and the target
if (return_method != return_method_normal
|| (stack_temporaries && class_or_union_p (values_type)))
- {
- if (gdbarch_inner_than (gdbarch, 1, 2))
- {
- /* Stack grows downward. Align STRUCT_ADDR and SP after
- making space for the return value. */
- sp -= TYPE_LENGTH (values_type);
- if (gdbarch_frame_align_p (gdbarch))
- sp = gdbarch_frame_align (gdbarch, sp);
- struct_addr = sp;
- }
- else
- {
- /* Stack grows upward. Align the frame, allocate space, and
- then again, re-align the frame??? */
- if (gdbarch_frame_align_p (gdbarch))
- sp = gdbarch_frame_align (gdbarch, sp);
- struct_addr = sp;
- sp += TYPE_LENGTH (values_type);
- if (gdbarch_frame_align_p (gdbarch))
- sp = gdbarch_frame_align (gdbarch, sp);
- }
- }
+ struct_addr = reserve_stack_space (values_type, sp);
std::vector<struct value *> new_args;
if (return_method == return_method_hidden_param)
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,
return_method != return_method_normal,
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);
+ throw_exception (std::move (e));
}
}
void
_initialize_infcall (void)
{
+ add_setshow_boolean_cmd ("may-call-functions", no_class,
+ &may_call_functions_p, _("\
+Set permission to call functions in the program."), _("\
+Show permission to call functions in the program."), _("\
+When this permission is on, GDB may call functions in the program.\n\
+Otherwise, any sort of attempt to call a function in the program\n\
+will result in an error."),
+ NULL,
+ show_may_call_functions_p,
+ &setlist, &showlist);
+
add_setshow_boolean_cmd ("coerce-float-to-double", class_obscure,
&coerce_float_to_double_p, _("\
Set coercion of floats to doubles when calling functions."), _("\
-Show coercion of floats to doubles when calling functions"), _("\
+Show coercion of floats to doubles when calling functions."), _("\
Variables of type float should generally be converted to doubles before\n\
calling an unprototyped function, and left alone when calling a prototyped\n\
function. However, some older debug info formats do not provide enough\n\
information to determine that a function is prototyped. If this flag is\n\
set, GDB will perform the conversion for a function it considers\n\
unprototyped.\n\
-The default is to perform the conversion.\n"),
+The default is to perform the conversion."),
NULL,
show_coerce_float_to_double_p,
&setlist, &showlist);