/* Perform an inferior function call, for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1986-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "target.h"
#include "regcache.h"
#include "inferior.h"
-#include "gdb_assert.h"
+#include "infrun.h"
#include "block.h"
#include "gdbcore.h"
#include "language.h"
#include "objfiles.h"
#include "gdbcmd.h"
#include "command.h"
-#include "gdb_string.h"
#include "infcall.h"
#include "dummy-frame.h"
#include "ada-lang.h"
#include "gdbthread.h"
-#include "exceptions.h"
+#include "event-top.h"
+#include "observer.h"
/* If we can't find a function's name from its address,
we print this instead. */
The default is to stop in the frame where the signal was received. */
-int unwind_on_signal_p = 0;
+static int unwind_on_signal_p = 0;
static void
show_unwind_on_signal_p (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
struct value *new_value;
if (TYPE_CODE (arg_type) == TYPE_CODE_REF)
- return value_cast_pointers (type, arg);
+ return value_cast_pointers (type, arg, 0);
/* Cast the value to the reference's target type, and then
convert it back to a reference. This will issue an error
case TYPE_CODE_SET:
case TYPE_CODE_RANGE:
case TYPE_CODE_STRING:
- case TYPE_CODE_BITSTRING:
case TYPE_CODE_ERROR:
case TYPE_CODE_MEMBERPTR:
case TYPE_CODE_METHODPTR:
return value_cast (type, arg);
}
+/* Return the return type of a function with its first instruction exactly at
+ the PC address. Return NULL otherwise. */
+
+static struct type *
+find_function_return_type (CORE_ADDR pc)
+{
+ struct symbol *sym = find_pc_function (pc);
+
+ if (sym != NULL && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == pc
+ && SYMBOL_TYPE (sym) != NULL)
+ return TYPE_TARGET_TYPE (SYMBOL_TYPE (sym));
+
+ return NULL;
+}
+
/* Determine a function's address and its return type from its value.
Calls error() if the function is not valid for calling. */
{
struct type *ftype = check_typedef (value_type (function));
struct gdbarch *gdbarch = get_type_arch (ftype);
- enum type_code code = TYPE_CODE (ftype);
struct type *value_type = NULL;
- CORE_ADDR funaddr;
+ /* Initialize it just to avoid a GCC false warning. */
+ CORE_ADDR funaddr = 0;
/* If it's a member function, just look at the function
part of it. */
/* Determine address to call. */
- if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
- {
- funaddr = value_address (function);
- value_type = TYPE_TARGET_TYPE (ftype);
- }
- else if (code == TYPE_CODE_PTR)
+ if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+ || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ funaddr = value_address (function);
+ else if (TYPE_CODE (ftype) == 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,
+ ¤t_target);
+ }
+ if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+ || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ {
+ value_type = TYPE_TARGET_TYPE (ftype);
+
+ if (TYPE_GNU_IFUNC (ftype))
{
- funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
- ¤t_target);
- value_type = TYPE_TARGET_TYPE (ftype);
+ funaddr = gnu_ifunc_resolve_addr (gdbarch, funaddr);
+
+ /* Skip querying the function symbol if no RETVAL_TYPE has been
+ asked for. */
+ if (retval_type)
+ value_type = find_function_return_type (funaddr);
}
}
- else if (code == TYPE_CODE_INT)
+ else if (TYPE_CODE (ftype) == TYPE_CODE_INT)
{
/* Handle the case of functions lacking debugging info.
Their values are characters since their addresses are char. */
{
/* Try the minimal symbols. */
- struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr);
+ struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (funaddr);
- if (msymbol)
- return SYMBOL_PRINT_NAME (msymbol);
+ if (msymbol.minsym)
+ return MSYMBOL_PRINT_NAME (msymbol.minsym);
}
{
static struct gdb_exception
run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
{
- volatile struct gdb_exception e;
- int saved_async = 0;
+ struct gdb_exception caught_error = exception_none;
int saved_in_infcall = call_thread->control.in_infcall;
ptid_t call_thread_ptid = call_thread->ptid;
- char *saved_target_shortname = xstrdup (target_shortname);
+ int saved_sync_execution = sync_execution;
+ int was_running = call_thread->state == THREAD_RUNNING;
+
+ /* Infcalls run synchronously, in the foreground. */
+ if (target_can_async_p ())
+ sync_execution = 1;
call_thread->control.in_infcall = 1;
- clear_proceed_status ();
+ clear_proceed_status (0);
disable_watchpoints_before_interactive_call_start ();
- /* We want stop_registers, please... */
+ /* We want to print return value, please... */
call_thread->control.proceed_to_finish = 1;
- if (target_can_async_p ())
- saved_async = target_async_mask (0);
+ TRY
+ {
+ int was_sync = sync_execution;
+
+ proceed (real_pc, GDB_SIGNAL_0);
- TRY_CATCH (e, RETURN_MASK_ALL)
- proceed (real_pc, TARGET_SIGNAL_0, 0);
+ /* Inferior function calls are always synchronous, even if the
+ target supports asynchronous execution. Do here what
+ `proceed' itself does in sync mode. */
+ if (target_can_async_p ())
+ {
+ wait_for_inferior ();
+ normal_stop ();
+ /* If GDB was previously in sync execution mode, then ensure
+ that it remains so. normal_stop calls
+ async_enable_stdin, so reset it again here. In other
+ cases, stdin will be re-enabled by
+ inferior_event_handler, when an exception is thrown. */
+ if (was_sync)
+ async_disable_stdin ();
+ }
+ }
+ CATCH (e, RETURN_MASK_ALL)
+ {
+ caught_error = e;
+ }
+ END_CATCH
/* 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);
- /* Don't restore the async mask if the target has changed,
- saved_async is for the original target. */
- if (saved_async
- && strcmp (saved_target_shortname, target_shortname) == 0)
- target_async_mask (saved_async);
+ /* 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
+ they were before the call. Note that we must also finish the
+ state of new threads that might have spawned while the call was
+ running. The main cases to handle are:
+
+ - "(gdb) print foo ()", or any other command that evaluates an
+ expression at the prompt. (The thread was marked stopped before.)
+
+ - "(gdb) break foo if return_false()" or similar cases where we
+ do an infcall while handling an event (while the thread is still
+ marked running). In this example, whether the condition
+ evaluates true and thus we'll present a user-visible stop is
+ decided elsewhere. */
+ if (!was_running
+ && ptid_equal (call_thread_ptid, inferior_ptid)
+ && stop_stack_dummy == STOP_STACK_DUMMY)
+ finish_thread_state (user_visible_resume_ptid (0));
enable_watchpoints_after_interactive_call_stop ();
If all error()s out of proceed ended up calling normal_stop
(and perhaps they should; it already does in the special case
of error out of resume()), then we wouldn't need this. */
- if (e.reason < 0)
+ if (caught_error.reason < 0)
{
if (call_thread != NULL)
breakpoint_auto_delete (call_thread->control.stop_bpstat);
if (call_thread != NULL)
call_thread->control.in_infcall = saved_in_infcall;
- xfree (saved_target_shortname);
+ sync_execution = saved_sync_execution;
- return e;
+ return caught_error;
}
/* A cleanup function that calls delete_std_terminate_breakpoint. */
delete_std_terminate_breakpoint ();
}
+/* See infcall.h. */
+
+struct value *
+call_function_by_hand (struct value *function, int nargs, struct value **args)
+{
+ return call_function_by_hand_dummy (function, nargs, args, NULL, NULL);
+}
+
+/* Data for dummy_frame_context_saver. Structure can be freed only
+ after both dummy_frame_context_saver_dtor and
+ dummy_frame_context_saver_drop have been called for it. */
+
+struct dummy_frame_context_saver
+{
+ /* Inferior registers fetched before associated dummy_frame got freed
+ and before any other destructors of associated dummy_frame got called.
+ It is initialized to NULL. */
+ struct regcache *retbuf;
+
+ /* It is 1 if this dummy_frame_context_saver_drop has been already
+ called. */
+ int drop_done;
+};
+
+/* Free struct dummy_frame_context_saver. */
+
+static void
+dummy_frame_context_saver_free (struct dummy_frame_context_saver *saver)
+{
+ regcache_xfree (saver->retbuf);
+ xfree (saver);
+}
+
+/* Destructor for associated dummy_frame. */
+
+static void
+dummy_frame_context_saver_dtor (void *data_voidp, int registers_valid)
+{
+ struct dummy_frame_context_saver *data = data_voidp;
+
+ gdb_assert (data->retbuf == NULL);
+
+ if (data->drop_done)
+ dummy_frame_context_saver_free (data);
+ else if (registers_valid)
+ data->retbuf = regcache_dup (get_current_regcache ());
+}
+
+/* Caller is no longer interested in this
+ struct dummy_frame_context_saver. After its associated dummy_frame
+ gets freed struct dummy_frame_context_saver can be also freed. */
+
+void
+dummy_frame_context_saver_drop (struct dummy_frame_context_saver *saver)
+{
+ saver->drop_done = 1;
+
+ if (!find_dummy_frame_dtor (dummy_frame_context_saver_dtor, saver))
+ dummy_frame_context_saver_free (saver);
+}
+
+/* Stub dummy_frame_context_saver_drop compatible with make_cleanup. */
+
+void
+dummy_frame_context_saver_cleanup (void *data)
+{
+ struct dummy_frame_context_saver *saver = data;
+
+ dummy_frame_context_saver_drop (saver);
+}
+
+/* Fetch RETBUF field of possibly opaque DTOR_DATA.
+ RETBUF must not be NULL. */
+
+struct regcache *
+dummy_frame_context_saver_get_regs (struct dummy_frame_context_saver *saver)
+{
+ gdb_assert (saver->retbuf != NULL);
+ return saver->retbuf;
+}
+
+/* Register provider of inferior registers at the time DUMMY_ID frame of
+ PTID gets freed (before inferior registers get restored to those
+ before dummy_frame). */
+
+struct dummy_frame_context_saver *
+dummy_frame_context_saver_setup (struct frame_id dummy_id, ptid_t ptid)
+{
+ struct dummy_frame_context_saver *saver;
+
+ saver = xmalloc (sizeof (*saver));
+ saver->retbuf = NULL;
+ saver->drop_done = 0;
+ register_dummy_frame_dtor (dummy_id, inferior_ptid,
+ dummy_frame_context_saver_dtor, saver);
+ return saver;
+}
+
/* All this stuff with a dummy frame may seem unnecessarily complicated
(why not just save registers in GDB?). The purpose of pushing a dummy
frame which looks just like a real frame is so that if you call a
ARGS is modified to contain coerced values. */
struct value *
-call_function_by_hand (struct value *function, int nargs, struct value **args)
+call_function_by_hand_dummy (struct value *function,
+ int nargs, struct value **args,
+ dummy_frame_dtor_ftype *dummy_dtor,
+ void *dummy_dtor_data)
{
CORE_ADDR sp;
struct type *values_type, *target_values_type;
- unsigned char struct_return = 0, lang_struct_return = 0;
+ unsigned char struct_return = 0, hidden_first_param_p = 0;
CORE_ADDR struct_addr = 0;
struct infcall_control_state *inf_status;
struct cleanup *inf_status_cleanup;
ptid_t call_thread_ptid;
struct gdb_exception e;
char name_buf[RAW_FUNCTION_ADDRESS_SIZE];
+ int stack_temporaries = thread_stack_temporaries_enabled_p (inferior_ptid);
+ struct dummy_frame_context_saver *context_saver;
+ struct cleanup *context_saver_cleanup;
if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
if (get_traceframe_number () >= 0)
error (_("May not call functions while looking at trace frames."));
+ if (execution_direction == EXEC_REVERSE)
+ error (_("Cannot call functions in reverse mode."));
+
frame = get_current_frame ();
gdbarch = get_frame_arch (frame);
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
+ the evaluation of an expression. */
+ if (stack_temporaries)
+ {
+ struct value *lastval;
+
+ lastval = get_last_thread_stack_temporary (inferior_ptid);
+ if (lastval != NULL)
+ {
+ CORE_ADDR lastval_addr = value_address (lastval);
+
+ if (gdbarch_inner_than (gdbarch, 1, 2))
+ {
+ gdb_assert (sp >= lastval_addr);
+ sp = lastval_addr;
+ }
+ else
+ {
+ gdb_assert (sp <= lastval_addr);
+ sp = lastval_addr + TYPE_LENGTH (value_type (lastval));
+ }
+
+ if (gdbarch_frame_align_p (gdbarch))
+ sp = gdbarch_frame_align (gdbarch, sp);
+ }
+ }
}
funaddr = find_function_addr (function, &values_type);
if (!values_type)
values_type = builtin_type (gdbarch)->builtin_int;
- CHECK_TYPEDEF (values_type);
+ 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?
the first argument is passed in out0 but the hidden structure
return pointer would normally be passed in r8. */
- if (language_pass_by_reference (values_type))
+ if (gdbarch_return_in_first_hidden_param_p (gdbarch, values_type))
{
- lang_struct_return = 1;
+ hidden_first_param_p = 1;
/* Tell the target specific argument pushing routine not to
expect a value. */
}
else
{
- struct_return = using_struct_return (gdbarch,
- value_type (function), values_type);
+ struct_return = using_struct_return (gdbarch, function, values_type);
target_values_type = values_type;
}
+ observer_notify_inferior_call_pre (inferior_ptid, funaddr);
+
/* Determine the location of the breakpoint (and possibly other
stuff) that the called function will return to. The SPARC, for a
function returning a structure or union, needs to make space for
not just the breakpoint but also an extra word containing the
size (?) of the structure being passed. */
- /* The actual breakpoint (at BP_ADDR) is inserted separatly so there
- is no need to write that out. */
-
switch (gdbarch_call_dummy_location (gdbarch))
{
case ON_STACK:
- sp = push_dummy_code (gdbarch, sp, funaddr,
- args, nargs, target_values_type,
- &real_pc, &bp_addr, get_current_regcache ());
+ {
+ const gdb_byte *bp_bytes;
+ CORE_ADDR bp_addr_as_address;
+ int bp_size;
+
+ /* 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,
+ target_values_type, &real_pc, &bp_addr,
+ get_current_regcache ());
+
+ /* Write a legitimate instruction at the point where the infcall
+ breakpoint is going to be inserted. While this instruction
+ is never going to be executed, a user investigating the
+ memory from GDB would see this instruction instead of random
+ uninitialized bytes. We chose the breakpoint instruction
+ as it may look as the most logical one to the user and also
+ valgrind 3.7.0 needs it for proper vgdb inferior calls.
+
+ If software breakpoints are unsupported for this target we
+ leave the user visible memory content uninitialized. */
+
+ bp_addr_as_address = bp_addr;
+ bp_bytes = gdbarch_breakpoint_from_pc (gdbarch, &bp_addr_as_address,
+ &bp_size);
+ if (bp_bytes != NULL)
+ write_memory (bp_addr_as_address, bp_bytes, bp_size);
+ }
break;
case AT_ENTRY_POINT:
{
real_pc = funaddr;
dummy_addr = entry_point_address ();
+
/* A call dummy always consists of just a single breakpoint, so
- its address is the same as the address of the dummy. */
- bp_addr = dummy_addr;
- break;
- }
- case AT_SYMBOL:
- /* Some executables define a symbol __CALL_DUMMY_ADDRESS whose
- address is the location where the breakpoint should be
- placed. Once all targets are using the overhauled frame code
- this can be deleted - ON_STACK is a better option. */
- {
- struct minimal_symbol *sym;
- CORE_ADDR dummy_addr;
+ its address is the same as the address of the dummy.
- sym = lookup_minimal_symbol ("__CALL_DUMMY_ADDRESS", NULL, NULL);
- real_pc = funaddr;
- if (sym)
- {
- dummy_addr = SYMBOL_VALUE_ADDRESS (sym);
- /* Make certain that the address points at real code, and not
- a function descriptor. */
- dummy_addr = gdbarch_convert_from_func_ptr_addr (gdbarch,
- dummy_addr,
- ¤t_target);
- }
- else
- dummy_addr = entry_point_address ();
- /* A call dummy always consists of just a single breakpoint,
- so it's address is the same as the address of the dummy. */
+ The actual breakpoint is inserted separatly so there is no need to
+ write that out. */
bp_addr = dummy_addr;
break;
}
/* Reserve space for the return structure to be written on the
stack, if necessary. Make certain that the value is correctly
- aligned. */
+ aligned.
- if (struct_return || lang_struct_return)
- {
- int len = TYPE_LENGTH (values_type);
+ While evaluating expressions, we reserve space on the stack for
+ return values of class type even if the language ABI and the target
+ ABI do not require that the return value be passed as a hidden first
+ argument. This is because we want to store the return value as an
+ on-stack temporary while the expression is being evaluated. This
+ enables us to have chained function calls in expressions.
+
+ Keeping the return values as on-stack temporaries while the expression
+ is being evaluated is OK because the thread is stopped until the
+ expression is completely evaluated. */
+ if (struct_return || hidden_first_param_p
+ || (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 -= len;
+ sp -= TYPE_LENGTH (values_type);
if (gdbarch_frame_align_p (gdbarch))
sp = gdbarch_frame_align (gdbarch, sp);
struct_addr = sp;
if (gdbarch_frame_align_p (gdbarch))
sp = gdbarch_frame_align (gdbarch, sp);
struct_addr = sp;
- sp += len;
+ sp += TYPE_LENGTH (values_type);
if (gdbarch_frame_align_p (gdbarch))
sp = gdbarch_frame_align (gdbarch, sp);
}
}
- if (lang_struct_return)
+ if (hidden_first_param_p)
{
struct value **new_args;
inferior. That way it breaks when it returns. */
{
- struct breakpoint *bpt;
+ struct breakpoint *bpt, *longjmp_b;
struct symtab_and_line sal;
init_sal (&sal); /* initialize to zeroes */
PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by
dummy_id to form the frame ID's stack address. */
bpt = set_momentary_breakpoint (gdbarch, sal, dummy_id, bp_call_dummy);
+
+ /* set_momentary_breakpoint invalidates FRAME. */
+ frame = NULL;
+
bpt->disposition = disp_del;
+ gdb_assert (bpt->related_breakpoint == bpt);
+
+ longjmp_b = set_longjmp_breakpoint_for_call_dummy ();
+ if (longjmp_b)
+ {
+ /* Link BPT into the chain of LONGJMP_B. */
+ bpt->related_breakpoint = longjmp_b;
+ while (longjmp_b->related_breakpoint != bpt->related_breakpoint)
+ longjmp_b = longjmp_b->related_breakpoint;
+ longjmp_b->related_breakpoint = bpt;
+ }
}
/* Create a breakpoint in std::terminate.
if (unwind_on_terminating_exception_p)
set_std_terminate_breakpoint ();
- /* 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);
-
/* 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);
+ if (dummy_dtor != NULL)
+ register_dummy_frame_dtor (dummy_id, inferior_ptid,
+ dummy_dtor, dummy_dtor_data);
+
+ /* dummy_frame_context_saver_setup must be called last so that its
+ saving of inferior registers gets called first (before possible
+ DUMMY_DTOR destructor). */
+ context_saver = dummy_frame_context_saver_setup (dummy_id, inferior_ptid);
+ context_saver_cleanup = make_cleanup (dummy_frame_context_saver_cleanup,
+ context_saver);
+
/* Register a clean-up for unwind_on_terminating_exception_breakpoint. */
terminate_bp_cleanup = make_cleanup (cleanup_delete_std_terminate_breakpoint,
NULL);
e = run_inferior_call (tp, real_pc);
}
+ observer_notify_inferior_call_post (call_thread_ptid, funaddr);
+
/* Rethrow an error if we got one trying to run the inferior. */
if (e.reason < 0)
if (stopped_by_random_signal || stop_stack_dummy != STOP_STACK_DUMMY)
{
- const char *name = get_function_name (funaddr,
- name_buf, sizeof (name_buf));
+ /* Make a copy as NAME may be in an objfile freed by dummy_frame_pop. */
+ char *name = xstrdup (get_function_name (funaddr,
+ name_buf, sizeof (name_buf)));
+ make_cleanup (xfree, name);
+
if (stopped_by_random_signal)
{
/* We must get back to the frame we were before the
dummy call. */
- dummy_frame_pop (dummy_id);
+ dummy_frame_pop (dummy_id, call_thread_ptid);
/* We also need to restore inferior status to that before the
dummy call. */
{
/* We must get back to the frame we were before the dummy
call. */
- dummy_frame_pop (dummy_id);
+ dummy_frame_pop (dummy_id, call_thread_ptid);
/* We also need to restore inferior status to that before
the dummy call. */
and the dummy frame has already been popped. */
{
- struct address_space *aspace = get_regcache_aspace (stop_registers);
- struct regcache *retbuf = regcache_xmalloc (gdbarch, aspace);
- struct cleanup *retbuf_cleanup = make_cleanup_regcache_xfree (retbuf);
struct value *retval = NULL;
- regcache_cpy_no_passthrough (retbuf, stop_registers);
-
/* Inferior call is successful. Restore the inferior status.
At this stage, leave the RETBUF alone. */
restore_infcall_control_state (inf_status);
- /* Figure out the value returned by the function. */
-
- if (lang_struct_return)
- retval = value_at (values_type, struct_addr);
- else if (TYPE_CODE (target_values_type) == TYPE_CODE_VOID)
+ if (TYPE_CODE (values_type) == TYPE_CODE_VOID)
+ retval = allocate_value (values_type);
+ else if (struct_return || hidden_first_param_p)
{
- /* If the function returns void, don't bother fetching the
- return value. */
- retval = allocate_value (values_type);
+ if (stack_temporaries)
+ {
+ retval = value_from_contents_and_address (values_type, NULL,
+ struct_addr);
+ push_thread_stack_temporary (inferior_ptid, retval);
+ }
+ else
+ {
+ retval = allocate_value (values_type);
+ read_value_memory (retval, 0, 1, struct_addr,
+ value_contents_raw (retval),
+ TYPE_LENGTH (values_type));
+ }
}
else
{
- switch (gdbarch_return_value (gdbarch, value_type (function),
- target_values_type, NULL, NULL, NULL))
+ retval = allocate_value (values_type);
+ gdbarch_return_value (gdbarch, function, values_type,
+ dummy_frame_context_saver_get_regs (context_saver),
+ value_contents_raw (retval), NULL);
+ if (stack_temporaries && class_or_union_p (values_type))
{
- case RETURN_VALUE_REGISTER_CONVENTION:
- case RETURN_VALUE_ABI_RETURNS_ADDRESS:
- case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
- retval = allocate_value (values_type);
- gdbarch_return_value (gdbarch, value_type (function), values_type,
- retbuf, value_contents_raw (retval), NULL);
- break;
- case RETURN_VALUE_STRUCT_CONVENTION:
- retval = value_at (values_type, struct_addr);
- break;
+ /* Values of class type returned in registers are copied onto
+ the stack and their lval_type set to lval_memory. This is
+ required because further evaluation of the expression
+ could potentially invoke methods on the return value
+ requiring GDB to evaluate the "this" pointer. To evaluate
+ the this pointer, GDB needs the memory address of the
+ value. */
+ value_force_lval (retval, struct_addr);
+ push_thread_stack_temporary (inferior_ptid, retval);
}
}
- do_cleanups (retbuf_cleanup);
+ do_cleanups (context_saver_cleanup);
gdb_assert (retval);
return retval;