/* Perform an inferior function call, for GDB, the GNU debugger.
- Copyright (C) 1986-2012 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. */
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:
{
/* 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;
+ struct gdb_exception caught_error = exception_none;
int saved_in_infcall = call_thread->control.in_infcall;
ptid_t call_thread_ptid = call_thread->ptid;
+ 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;
- TRY_CATCH (e, RETURN_MASK_ALL)
+ TRY
{
- proceed (real_pc, GDB_SIGNAL_0, 0);
+ int was_sync = sync_execution;
+
+ proceed (real_pc, GDB_SIGNAL_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 () && is_running (inferior_ptid))
+ 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);
+ /* 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 ();
/* Call breakpoint_auto_delete on the current contents of the bpstat
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;
- return e;
+ sync_execution = saved_sync_execution;
+
+ 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 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. */
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. */
+ its 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 */
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. */
- retval = allocate_value (values_type);
-
- if (lang_struct_return)
- read_value_memory (retval, 0, 1, struct_addr,
- value_contents_raw (retval),
- TYPE_LENGTH (values_type));
- 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. */
- switch (gdbarch_return_value (gdbarch, function, target_values_type,
- NULL, NULL, NULL))
+ if (stack_temporaries)
+ {
+ retval = value_from_contents_and_address (values_type, NULL,
+ struct_addr);
+ push_thread_stack_temporary (inferior_ptid, retval);
+ }
+ else
{
- case RETURN_VALUE_REGISTER_CONVENTION:
- case RETURN_VALUE_ABI_RETURNS_ADDRESS:
- case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
- gdbarch_return_value (gdbarch, function, values_type,
- retbuf, value_contents_raw (retval), NULL);
- break;
- case RETURN_VALUE_STRUCT_CONVENTION:
+ retval = allocate_value (values_type);
read_value_memory (retval, 0, 1, struct_addr,
value_contents_raw (retval),
TYPE_LENGTH (values_type));
- break;
+ }
+ }
+ else
+ {
+ 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))
+ {
+ /* 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;