X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfcall.c;h=5553fc9779179b32504b8382ee168437b0dd960f;hb=bda13cdcf0db4d9cee648bfa0bfc7f1a4415d2a7;hp=b13f5b61d96e84f5cc892d2f1a834169a0f1ec2b;hpb=f6ac5f3d63e03a81c4ff3749aba234961cc9090e;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infcall.c b/gdb/infcall.c index b13f5b61d9..5553fc9779 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-2019 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,7 @@ #include "interps.h" #include "thread-fsm.h" #include +#include "gdbsupport/scope-exit.h" /* If we can't find a function's name from its address, we print this instead. */ @@ -53,6 +55,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 +86,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 +104,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 +127,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 +142,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 @@ -256,7 +269,7 @@ find_function_addr (struct value *function, if (TYPE_CODE (ftype) == TYPE_CODE_FUNC || TYPE_CODE (ftype) == TYPE_CODE_METHOD) funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr, - target_stack); + current_top_target ()); } if (TYPE_CODE (ftype) == TYPE_CODE_FUNC || TYPE_CODE (ftype) == TYPE_CODE_METHOD) @@ -307,8 +320,9 @@ find_function_addr (struct value *function, funaddr = value_as_address (value_addr (function)); nfunaddr = funaddr; - funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr, - target_stack); + funaddr + = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr, + current_top_target ()); if (funaddr != nfunaddr) found_descriptor = 1; } @@ -333,7 +347,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) @@ -341,7 +355,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); } @@ -372,7 +387,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 (); } { @@ -380,17 +395,15 @@ 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 (); } { - char *tmp = xstrprintf (_(RAW_FUNCTION_ADDRESS_FORMAT), - hex_string (funaddr)); + std::string tmp = string_printf (_(RAW_FUNCTION_ADDRESS_FORMAT), + hex_string (funaddr)); - gdb_assert (strlen (tmp) + 1 <= buf_size); - strcpy (buf, tmp); - xfree (tmp); - return buf; + gdb_assert (tmp.length () + 1 <= buf_size); + return strcpy (buf, tmp.c_str ()); } } @@ -421,7 +434,8 @@ static struct value * get_call_return_value (struct call_return_meta_info *ri) { struct value *retval = NULL; - bool stack_temporaries = thread_stack_temporaries_enabled_p (inferior_ptid); + thread_info *thr = inferior_thread (); + bool stack_temporaries = thread_stack_temporaries_enabled_p (thr); if (TYPE_CODE (ri->value_type) == TYPE_CODE_VOID) retval = allocate_value (ri->value_type); @@ -431,7 +445,7 @@ get_call_return_value (struct call_return_meta_info *ri) { retval = value_from_contents_and_address (ri->value_type, NULL, ri->struct_addr); - push_thread_stack_temporary (inferior_ptid, retval); + push_thread_stack_temporary (thr, retval); } else { @@ -457,7 +471,7 @@ get_call_return_value (struct call_return_meta_info *ri) the this pointer, GDB needs the memory address of the value. */ value_force_lval (retval, ri->struct_addr); - push_thread_stack_temporary (inferior_ptid, retval); + push_thread_stack_temporary (thr, retval); } } @@ -468,106 +482,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 +577,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 +599,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 +614,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 @@ -636,10 +630,6 @@ run_inferior_call (struct call_thread_fsm *sm, ui_register_input_event_handler (current_ui); current_ui->async = saved_ui_async; - /* 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); - /* If the infcall does NOT succeed, normal_stop will have already finished the thread states. However, on success, normal_stop defers here, so that we can set back the thread states to what @@ -656,7 +646,7 @@ run_inferior_call (struct call_thread_fsm *sm, evaluates true and thus we'll present a user-visible stop is decided elsewhere. */ if (!was_running - && ptid_equal (call_thread_ptid, inferior_ptid) + && call_thread_ptid == inferior_ptid && stop_stack_dummy == STOP_STACK_DUMMY) finish_thread_state (user_visible_resume_ptid (0)); @@ -669,21 +659,49 @@ run_inferior_call (struct call_thread_fsm *sm, of error out of resume()), then we wouldn't need this. */ if (caught_error.reason < 0) { - if (call_thread != NULL) + if (call_thread->state != THREAD_EXITED) breakpoint_auto_delete (call_thread->control.stop_bpstat); } - if (call_thread != NULL) - call_thread->control.in_infcall = saved_in_infcall; + call_thread->control.in_infcall = saved_in_infcall; 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. */ @@ -691,10 +709,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 @@ -707,7 +725,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 @@ -718,27 +736,26 @@ 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]; - bool stack_temporaries = thread_stack_temporaries_enabled_p (inferior_ptid); + + if (!may_call_functions_p) + error (_("Cannot call functions in the program: " + "may-call-functions is off.")); if (!target_has_execution) noprocess (); @@ -749,25 +766,51 @@ call_function_by_hand_dummy (struct value *function, if (execution_direction == EXEC_REVERSE) error (_("Cannot call functions in reverse mode.")); + /* We're going to run the target, and inspect the thread's state + afterwards. Hold a strong reference so that the pointer remains + valid even if the thread exits. */ + thread_info_ref call_thread + = thread_info_ref::new_reference (inferior_thread ()); + + bool stack_temporaries = thread_stack_temporaries_enabled_p (call_thread.get ()); + frame = get_current_frame (); gdbarch = get_frame_arch (frame); 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. */ { @@ -798,7 +841,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. @@ -841,7 +884,7 @@ call_function_by_hand_dummy (struct value *function, { struct value *lastval; - lastval = get_last_thread_stack_temporary (inferior_ptid); + lastval = get_last_thread_stack_temporary (call_thread.get ()); if (lastval != NULL) { CORE_ADDR lastval_addr = value_address (lastval); @@ -863,37 +906,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. */ @@ -901,7 +918,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; } @@ -924,7 +942,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 ()); @@ -965,57 +983,49 @@ 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; - - 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; - args[i] = value_arg_coerce (gdbarch, args[i], - param_type, prototyped, &sp); + args[i] = value_arg_coerce (gdbarch, args[i], + param_type, prototyped); - if (param_type != NULL && language_pass_by_reference (param_type)) - args[i] = value_addr (args[i]); - } - } + 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 @@ -1028,48 +1038,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 @@ -1128,41 +1117,32 @@ 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, inferior_ptid); + dummy_frame_push (caller_state.release (), &dummy_id, call_thread.get ()); if (dummy_dtor != NULL) - register_dummy_frame_dtor (dummy_id, inferior_ptid, + 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 just below is the place to chop this function in two.. */ - /* TP is invalid after run_inferior_call returns, so enclose this - in a block so that it's only in scope during the time it's valid. */ { - struct thread_info *tp = inferior_thread (); struct thread_fsm *saved_sm; struct call_thread_fsm *sm; /* Save the current FSM. We'll override it. */ - saved_sm = tp->thread_fsm; - tp->thread_fsm = NULL; + saved_sm = call_thread->thread_fsm; + call_thread->thread_fsm = NULL; /* Save this thread's ptid, we need it later but the thread may have exited. */ - call_thread_ptid = tp->ptid; + call_thread_ptid = call_thread->ptid; /* Run the inferior until it stops. */ @@ -1170,23 +1150,22 @@ 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, tp, real_pc); + e = run_inferior_call (sm, call_thread.get (), real_pc); gdb::observers::inferior_call_post.notify (call_thread_ptid, funaddr); - tp = find_thread_ptid (call_thread_ptid); - if (tp != NULL) + if (call_thread->state != THREAD_EXITED) { /* The FSM should still be the same. */ - gdb_assert (tp->thread_fsm == &sm->thread_fsm); + gdb_assert (call_thread->thread_fsm == sm); - if (thread_fsm_finished_p (tp->thread_fsm)) + if (call_thread->thread_fsm->finished_p ()) { struct value *retval; @@ -1194,28 +1173,29 @@ call_function_by_hand_dummy (struct value *function, which runs its destructors and restores the inferior's suspend state, and restore the inferior control state. */ - dummy_frame_pop (dummy_id, call_thread_ptid); - restore_infcall_control_state (inf_status); + dummy_frame_pop (dummy_id, call_thread.get ()); + 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 (tp->thread_fsm, tp); - thread_fsm_delete (tp->thread_fsm); - tp->thread_fsm = saved_sm; + 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. */ - tp->thread_fsm = saved_sm; + /* 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; } } @@ -1226,7 +1206,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 @@ -1240,10 +1220,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)); } } @@ -1257,7 +1237,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 @@ -1270,7 +1250,7 @@ When the function is done executing, GDB will silently stop."), name); } - if (! ptid_equal (call_thread_ptid, inferior_ptid)) + if (call_thread_ptid != inferior_ptid) { const char *name = get_function_name (funaddr, name_buf, sizeof (name_buf)); @@ -1279,7 +1259,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) @@ -1316,11 +1296,11 @@ When the function is done executing, GDB will silently stop."), /* We must get back to the frame we were before the dummy call. */ - dummy_frame_pop (dummy_id, call_thread_ptid); + dummy_frame_pop (dummy_id, call_thread.get ()); /* 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. */ @@ -1338,7 +1318,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. */ @@ -1357,11 +1337,11 @@ When the function is done executing, GDB will silently stop."), { /* We must get back to the frame we were before the dummy call. */ - dummy_frame_pop (dummy_id, call_thread_ptid); + dummy_frame_pop (dummy_id, call_thread.get ()); /* 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\ @@ -1380,7 +1360,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." @@ -1407,17 +1387,28 @@ When the function is done executing, GDB will silently stop."), 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);