X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Finfcall.c;h=ca3347fbb9dec1852856c03b6f3dca4e5638112e;hb=328d42d87e97c75d6e52800bfd4bc1bfdfb745d2;hp=0d8d5b2178e8dcfbf54b9e3e47d2e9858dd85465;hpb=39bcc47c7e94c746d5acdb52f20f9617a6473292;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infcall.c b/gdb/infcall.c index 0d8d5b2178..ca3347fbb9 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-2019 Free Software Foundation, Inc. + Copyright (C) 1986-2021 Free Software Foundation, Inc. This file is part of GDB. @@ -42,12 +42,13 @@ #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. */ #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? @@ -145,13 +146,11 @@ show_unwind_on_terminating_exception_p (struct ui_file *file, int from_tty, 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)); @@ -170,7 +169,7 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, 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: @@ -185,7 +184,7 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, 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: @@ -199,8 +198,8 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, 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; @@ -218,10 +217,10 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, 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: @@ -252,7 +251,7 @@ find_function_addr (struct value *function, 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; @@ -261,22 +260,22 @@ find_function_addr (struct value *function, 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; @@ -304,10 +303,10 @@ find_function_addr (struct value *function, 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 @@ -322,9 +321,8 @@ find_function_addr (struct value *function, 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; } @@ -389,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 (); } { @@ -397,7 +395,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 (); } { @@ -439,7 +437,7 @@ get_call_return_value (struct call_return_meta_info *ri) 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) { @@ -650,7 +648,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 (); @@ -670,6 +669,69 @@ run_inferior_call (struct call_thread_fsm *sm, return caught_error; } +/* 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 +call_destructors (const std::list &dtors_to_invoke, + struct type *default_return_type) +{ + 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. */ struct value * @@ -691,7 +753,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 @@ -723,7 +785,7 @@ call_function_by_hand_dummy (struct value *function, 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) @@ -764,7 +826,7 @@ call_function_by_hand_dummy (struct value *function, 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. @@ -807,7 +869,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. @@ -840,8 +902,8 @@ call_function_by_hand_dummy (struct value *function, 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 @@ -851,7 +913,7 @@ call_function_by_hand_dummy (struct value *function, 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); @@ -949,6 +1011,12 @@ call_function_by_hand_dummy (struct value *function, internal_error (__FILE__, __LINE__, _("bad switch")); } + /* 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 (int i = args.size () - 1; i >= 0; i--) { int prototyped; @@ -956,9 +1024,9 @@ call_function_by_hand_dummy (struct value *function, /* 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 + if (TYPE_TARGET_TYPE (ftype) == NULL && ftype->num_fields () == 0 && default_return_type != NULL) { /* Calling a no-debug function with the return type @@ -973,26 +1041,109 @@ call_function_by_hand_dummy (struct value *function, */ 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; + value *original_arg = args[i]; args[i] = value_arg_coerce (gdbarch, args[i], - param_type, prototyped, &sp); + 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"), param_type->name ()); + + if (!info.destructible) + error (_("expression cannot be evaluated because the type '%s' " + "is not destructible"), param_type->name ()); + + 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), + 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?)"), param_type->name ()); + + call_function_by_hand (copy_ctor, default_return_type, + gdb::make_array_view (cctor_args, 2)); + } + + /* 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 (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?)"), param_type->name ()); + + value *dtor + = find_function_in_inferior (dtor_name, 0); - if (param_type != NULL && language_pass_by_reference (param_type)) - args[i] = value_addr (args[i]); + /* 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 @@ -1007,28 +1158,7 @@ call_function_by_hand_dummy (struct value *function, 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 (return_method == return_method_hidden_param) @@ -1176,6 +1306,10 @@ call_function_by_hand_dummy (struct value *function, maybe_remove_breakpoints (); gdb_assert (retval != NULL); + + /* Destruct the pass-by-ref argument clones. */ + call_destructors (dtors_to_invoke, default_return_type); + return retval; } @@ -1192,13 +1326,13 @@ call_function_by_hand_dummy (struct value *function, 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) { @@ -1218,7 +1352,7 @@ When the function is done executing, GDB will silently stop."), /* 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)); @@ -1228,8 +1362,8 @@ When the function is done executing, GDB will silently stop."), 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" @@ -1372,8 +1506,9 @@ 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, _("\