X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfcall.c;h=b13c781c9d46b7d4615d2b7cc20b934d1c65f9be;hb=b1468492c69335b023e6e4adf15ba0de0263812e;hp=b2d1205faaff6a16425334a5be35750e81e35f6e;hpb=528e15722bf67d126e17218708c0314bcfadbf6a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infcall.c b/gdb/infcall.c index b2d1205faa..b13c781c9d 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -1,6 +1,6 @@ /* Perform an inferior function call, for GDB, the GNU debugger. - Copyright (C) 1986-2018 Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -33,6 +33,7 @@ #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" @@ -40,6 +41,8 @@ #include "interps.h" #include "thread-fsm.h" #include +#include "gdbsupport/scope-exit.h" +#include /* If we can't find a function's name from its address, we print this instead. */ @@ -53,6 +56,17 @@ 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 @@ -73,7 +87,7 @@ 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) @@ -91,7 +105,7 @@ show_coerce_float_to_double_p (struct ui_file *file, int from_tty, 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) @@ -114,7 +128,7 @@ show_unwind_on_signal_p (struct ui_file *file, int from_tty, 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, @@ -129,25 +143,25 @@ 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 @@ -334,7 +348,7 @@ find_function_addr (struct value *function, static CORE_ADDR push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr, - struct value **args, int nargs, + gdb::array_view args, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr, struct regcache *regcache) @@ -342,7 +356,8 @@ push_dummy_code (struct gdbarch *gdbarch, 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); } @@ -373,7 +388,7 @@ 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); + return symbol->print_name (); } { @@ -381,7 +396,7 @@ get_function_name (CORE_ADDR funaddr, char *buf, int buf_size) 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 (); } { @@ -468,106 +483,87 @@ get_call_return_value (struct call_return_meta_info *ri) /* 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. @@ -582,7 +578,7 @@ static struct gdb_exception 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; @@ -604,14 +600,14 @@ run_inferior_call (struct call_thread_fsm *sm, /* 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); @@ -619,11 +615,10 @@ run_inferior_call (struct call_thread_fsm *sm, 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 @@ -654,7 +649,8 @@ run_inferior_call (struct call_thread_fsm *sm, if (!was_running && call_thread_ptid == inferior_ptid && stop_stack_dummy == STOP_STACK_DUMMY) - finish_thread_state (user_visible_resume_ptid (0)); + finish_thread_state (call_thread->inf->process_target (), + user_visible_resume_ptid (0)); enable_watchpoints_after_interactive_call_stop (); @@ -674,11 +670,67 @@ run_inferior_call (struct call_thread_fsm *sm, return caught_error; } -/* A cleanup function that calls delete_std_terminate_breakpoint. */ +/* 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) +{ + 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; +} + +/* The data structure which keeps a destructor function and + its implicit 'this' parameter. */ + +struct destructor_info +{ + destructor_info (struct value *function, struct value *self) + : function (function), self (self) { } + + struct value *function; + struct value *self; +}; + + +/* Auxiliary function that takes a list of destructor functions + with their 'this' parameters, and invokes the functions. */ + static void -cleanup_delete_std_terminate_breakpoint (void *ignore) +call_destructors (const std::list &dtors_to_invoke, + struct type *default_return_type) { - delete_std_terminate_breakpoint (); + for (auto vals : dtors_to_invoke) + { + call_function_by_hand (vals.function, default_return_type, + gdb::make_array_view (&(vals.self), 1)); + } } /* See infcall.h. */ @@ -686,10 +738,10 @@ cleanup_delete_std_terminate_breakpoint (void *ignore) struct value * call_function_by_hand (struct value *function, type *default_return_type, - int nargs, struct value **args) + gdb::array_view 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 @@ -702,7 +754,7 @@ call_function_by_hand (struct value *function, 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 @@ -713,27 +765,27 @@ call_function_by_hand (struct value *function, struct value * call_function_by_hand_dummy (struct value *function, type *default_return_type, - int nargs, struct value **args, + gdb::array_view 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; - struct infcall_control_state *inf_status; - struct cleanup *inf_status_cleanup; - struct infcall_suspend_state *caller_state; 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]; + if (!may_call_functions_p) + error (_("Cannot call functions in the program: " + "may-call-functions is off.")); + if (!target_has_execution) noprocess (); @@ -757,19 +809,37 @@ call_function_by_hand_dummy (struct value *function, if (!gdbarch_push_dummy_call_p (gdbarch)) error (_("This target does not support function calls.")); - /* A cleanup for the inferior status. + /* 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. */ - inf_status = save_infcall_control_state (); - inf_status_cleanup - = make_cleanup_restore_infcall_control_state (inf_status); + infcall_control_state_up inf_status (save_infcall_control_state ()); /* Save the caller's registers and other state associated with the inferior itself so that they can be restored once the callee returns. To allow nested calls the registers are (further - down) pushed onto a dummy frame stack. Include a cleanup (which - is tossed once the regcache has been pushed). */ - caller_state = save_infcall_suspend_state (); - make_cleanup_restore_infcall_suspend_state (caller_state); + down) pushed onto a dummy frame stack. This unique pointer + is released once the regcache has been pushed). */ + infcall_suspend_state_up caller_state (save_infcall_suspend_state ()); /* Ensure that the initial SP is correctly aligned. */ { @@ -800,7 +870,7 @@ call_function_by_hand_dummy (struct value *function, 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. @@ -865,37 +935,11 @@ call_function_by_hand_dummy (struct value *function, } } - 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 (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. */ @@ -903,7 +947,8 @@ call_function_by_hand_dummy (struct value *function, } 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; } @@ -926,7 +971,7 @@ call_function_by_hand_dummy (struct value *function, /* 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 ()); @@ -967,57 +1012,139 @@ call_function_by_hand_dummy (struct value *function, internal_error (__FILE__, __LINE__, _("bad switch")); } - if (nargs < TYPE_NFIELDS (ftype)) - error (_("Too few arguments in function call.")); - - { - int i; + /* Coerce the arguments and handle pass-by-reference. + We want to remember the destruction required for pass-by-ref values. + For these, store the dtor function and the 'this' argument + in DTORS_TO_INVOKE. */ + std::list dtors_to_invoke; - for (i = nargs - 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) + 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) + prototyped = 1; + if (TYPE_TARGET_TYPE (ftype) == NULL && TYPE_NFIELDS (ftype) == 0 + && default_return_type != NULL) + { + /* Calling a no-debug function with the return type + explicitly cast. Assume the function is prototyped, + with a prototype matching the types of the arguments. + E.g., with: + float mult (float v1, float v2) { return v1 * v2; } + This: + (gdb) p (float) mult (2.0f, 3.0f) + Is a simpler alternative to: + (gdb) p ((float (*) (float, float)) mult) (2.0f, 3.0f) + */ prototyped = 1; - if (TYPE_TARGET_TYPE (ftype) == NULL && TYPE_NFIELDS (ftype) == 0 - && default_return_type != NULL) - { - /* Calling a no-debug function with the return type - explicitly cast. Assume the function is prototyped, - with a prototype matching the types of the arguments. - E.g., with: - float mult (float v1, float v2) { return v1 * v2; } - This: - (gdb) p (float) mult (2.0f, 3.0f) - Is a simpler alternative to: - (gdb) p ((float (*) (float, float)) mult) (2.0f, 3.0f) - */ - prototyped = 1; - } - else if (i < TYPE_NFIELDS (ftype)) - prototyped = TYPE_PROTOTYPED (ftype); - else - prototyped = 0; + } + else if (i < TYPE_NFIELDS (ftype)) + prototyped = TYPE_PROTOTYPED (ftype); + else + prototyped = 0; - if (i < TYPE_NFIELDS (ftype)) - param_type = TYPE_FIELD_TYPE (ftype, i); - else - param_type = NULL; + if (i < TYPE_NFIELDS (ftype)) + param_type = TYPE_FIELD_TYPE (ftype, i); + else + param_type = NULL; + + value *original_arg = args[i]; + args[i] = value_arg_coerce (gdbarch, args[i], + param_type, prototyped); + + if (param_type == NULL) + continue; + + 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)); + + if (!info.destructible) + error (_("expression cannot be evaluated because the type '%s' " + "is not destructible"), TYPE_NAME (param_type)); + + if (info.trivially_copyable) + continue; + + /* Make a copy of the argument on the stack. If the argument is + trivially copy ctor'able, copy bit by bit. Otherwise, call + the copy ctor to initialize the clone. */ + CORE_ADDR addr = reserve_stack_space (param_type, sp); + value *clone + = value_from_contents_and_address (param_type, nullptr, addr); + push_thread_stack_temporary (call_thread.get (), clone); + value *clone_ptr + = value_from_pointer (lookup_pointer_type (param_type), addr); + + if (info.trivially_copy_constructible) + { + int length = TYPE_LENGTH (param_type); + write_memory (addr, value_contents (args[i]), 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, + &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)); + + call_function_by_hand (copy_ctor, default_return_type, + gdb::make_array_view (cctor_args, 2)); + } - args[i] = value_arg_coerce (gdbarch, args[i], - param_type, prototyped, &sp); + /* If the argument has a destructor, remember it so that we + invoke it after the infcall is complete. */ + if (!info.trivially_destructible) + { + /* Looking up the function via overload resolution does not + work because the compiler (in particular, gcc) adds an + artificial int parameter in some cases. So we look up + the function by using the "~" name. This should be OK + because there can be only one dtor definition. */ + const char *dtor_name = nullptr; + for (int fieldnum = 0; + fieldnum < TYPE_NFN_FIELDS (param_type); + fieldnum++) + { + fn_field *fn + = TYPE_FN_FIELDLIST1 (param_type, fieldnum); + const char *field_name + = TYPE_FN_FIELDLIST_NAME (param_type, fieldnum); - if (param_type != NULL && language_pass_by_reference (param_type)) - args[i] = value_addr (args[i]); - } - } + if (field_name[0] == '~') + dtor_name = TYPE_FN_FIELD_PHYSNAME (fn, 0); + } + + 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)); + + value *dtor + = find_function_in_inferior (dtor_name, 0); + + /* Insert the dtor to the front of the list to call them + in reverse order later. */ + dtors_to_invoke.emplace_front (dtor, clone_ptr); + } + + args[i] = clone_ptr; + } /* 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 @@ -1030,48 +1157,27 @@ call_function_by_hand_dummy (struct value *function, 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)) - { - /* 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 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 @@ -1130,22 +1236,16 @@ call_function_by_hand_dummy (struct value *function, if (unwind_on_terminating_exception_p) set_std_terminate_breakpoint (); - /* Discard both inf_status and caller_state cleanups. - From this point on we explicitly restore the associated state - or discard it. */ - discard_cleanups (inf_status_cleanup); - /* Everything's ready, push all the info needed to restore the caller (and identify the dummy-frame) onto the dummy-frame stack. */ - dummy_frame_push (caller_state, &dummy_id, call_thread.get ()); + dummy_frame_push (caller_state.release (), &dummy_id, call_thread.get ()); if (dummy_dtor != NULL) register_dummy_frame_dtor (dummy_id, call_thread.get (), 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 @@ -1169,10 +1269,10 @@ call_function_by_hand_dummy (struct value *function, 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); @@ -1182,9 +1282,9 @@ call_function_by_hand_dummy (struct value *function, 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; @@ -1193,26 +1293,31 @@ call_function_by_hand_dummy (struct value *function, suspend state, and restore the inferior control state. */ dummy_frame_pop (dummy_id, call_thread.get ()); - restore_infcall_control_state (inf_status); + restore_infcall_control_state (inf_status.release ()); /* Get the return value. */ retval = sm->return_value; /* 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); + + /* Destruct the pass-by-ref argument clones. */ + call_destructors (dtors_to_invoke, default_return_type); + 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; } } @@ -1224,7 +1329,7 @@ call_function_by_hand_dummy (struct value *function, const char *name = get_function_name (funaddr, name_buf, sizeof (name_buf)); - discard_infcall_control_state (inf_status); + 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 @@ -1238,10 +1343,10 @@ An error occurred while in a function called from GDB.\n\ 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)); } } @@ -1255,7 +1360,7 @@ When the function is done executing, GDB will silently stop."), /* If we try to restore the inferior status, we'll crash as the inferior is no longer running. */ - discard_infcall_control_state (inf_status); + 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 @@ -1277,7 +1382,7 @@ When the function is done executing, GDB will silently stop."), signal or breakpoint while our thread was running. There's no point in restoring the inferior status, we're in a different thread. */ - discard_infcall_control_state (inf_status); + discard_infcall_control_state (inf_status.release ()); /* Keep the dummy frame record, if the user switches back to the thread with the hand-call, we'll need it. */ if (stopped_by_random_signal) @@ -1318,7 +1423,7 @@ When the function is done executing, GDB will silently stop."), /* We also need to restore inferior status to that before the dummy call. */ - restore_infcall_control_state (inf_status); + restore_infcall_control_state (inf_status.release ()); /* FIXME: Insert a bunch of wrap_here; name can be very long if it's a C++ name with arguments and stuff. */ @@ -1336,7 +1441,7 @@ Evaluation of the expression containing the function\n\ (default). Discard inferior status, we're not at the same point we started at. */ - discard_infcall_control_state (inf_status); + discard_infcall_control_state (inf_status.release ()); /* FIXME: Insert a bunch of wrap_here; name can be very long if it's a C++ name with arguments and stuff. */ @@ -1359,7 +1464,7 @@ When the function is done executing, GDB will silently stop."), /* We also need to restore inferior status to that before the dummy call. */ - restore_infcall_control_state (inf_status); + restore_infcall_control_state (inf_status.release ()); error (_("\ The program being debugged entered a std::terminate call, most likely\n\ @@ -1378,7 +1483,7 @@ will be abandoned."), Keep the dummy frame, the user may want to examine its state. Discard inferior status, we're not at the same point we started at. */ - discard_infcall_control_state (inf_status); + discard_infcall_control_state (inf_status.release ()); /* The following error message used to say "The expression which contained the function call has been discarded." @@ -1402,20 +1507,32 @@ When the function is done executing, GDB will silently stop."), 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, _("\ +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);