if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
|| TYPE_CODE (ftype) == TYPE_CODE_METHOD)
funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
- ¤t_target);
+ current_top_target ());
}
if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
|| TYPE_CODE (ftype) == TYPE_CODE_METHOD)
funaddr = value_as_address (value_addr (function));
nfunaddr = funaddr;
- funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
- ¤t_target);
+ funaddr
+ = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
+ current_top_target ());
if (funaddr != nfunaddr)
found_descriptor = 1;
}
static CORE_ADDR
push_dummy_code (struct gdbarch *gdbarch,
CORE_ADDR sp, CORE_ADDR funaddr,
- struct value **args, int nargs,
+ gdb::array_view<value *> args,
struct type *value_type,
CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
struct regcache *regcache)
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);
}
}
{
- 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 ());
}
}
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);
{
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
{
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);
}
}
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
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));
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;
}
struct value *
call_function_by_hand (struct value *function,
type *default_return_type,
- int nargs, struct value **args)
+ gdb::array_view<value *> 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
struct value *
call_function_by_hand_dummy (struct value *function,
type *default_return_type,
- int nargs, struct value **args,
+ gdb::array_view<value *> 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;
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 (!target_has_execution)
noprocess ();
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.
+ /* 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. */
{
{
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);
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. */
}
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;
}
/* 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 ());
internal_error (__FILE__, __LINE__, _("bad switch"));
}
- if (nargs < TYPE_NFIELDS (ftype))
+ if (args.size () < 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, &sp);
- 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
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))
}
std::vector<struct value *> 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
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. */
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. */
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->thread_fsm);
- if (thread_fsm_finished_p (tp->thread_fsm))
+ if (thread_fsm_finished_p (call_thread->thread_fsm))
{
struct value *retval;
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;
+ thread_fsm_clean_up (call_thread->thread_fsm, call_thread.get ());
+ thread_fsm_delete (call_thread->thread_fsm);
+ call_thread->thread_fsm = saved_sm;
maybe_remove_breakpoints ();
/* Didn't complete. Restore previous state machine, and
handle the error. */
- tp->thread_fsm = saved_sm;
+ call_thread->thread_fsm = saved_sm;
}
}
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
/* 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
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));
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)
/* 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. */
(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. */
{
/* 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\
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."