#include "ada-lang.h"
#include "gdbthread.h"
#include "event-top.h"
-#include "observer.h"
+#include "observable.h"
#include "top.h"
#include "interps.h"
#include "thread-fsm.h"
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. */
+/* See infcall.h. */
CORE_ADDR
-find_function_addr (struct value *function, struct type **retval_type)
+find_function_addr (struct value *function,
+ struct type **retval_type,
+ struct type **function_type)
{
struct type *ftype = check_typedef (value_type (function));
struct gdbarch *gdbarch = get_type_arch (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);
+ current_top_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 = gnu_ifunc_resolve_addr (gdbarch, funaddr);
+ CORE_ADDR resolver_addr = funaddr;
+
+ /* Resolve the ifunc. Note this may call the resolver
+ function in the inferior. */
+ funaddr = gnu_ifunc_resolve_addr (gdbarch, resolver_addr);
- /* Skip querying the function symbol if no RETVAL_TYPE has been
- asked for. */
- if (retval_type)
- value_type = find_function_return_type (funaddr);
+ /* Skip querying the function symbol if no RETVAL_TYPE or
+ FUNCTION_TYPE have been asked for. */
+ if (retval_type != NULL || function_type != NULL)
+ {
+ type *target_ftype = find_function_type (funaddr);
+ /* If we don't have debug info for the target function,
+ see if we can instead extract the target function's
+ type from the type that the resolver returns. */
+ if (target_ftype == NULL)
+ target_ftype = find_gnu_ifunc_target_type (resolver_addr);
+ if (target_ftype != NULL)
+ {
+ value_type = TYPE_TARGET_TYPE (check_typedef (target_ftype));
+ ftype = target_ftype;
+ }
+ }
}
+ else
+ value_type = TYPE_TARGET_TYPE (ftype);
}
else if (TYPE_CODE (ftype) == TYPE_CODE_INT)
{
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;
}
if (retval_type != NULL)
*retval_type = value_type;
+ if (function_type != NULL)
+ *function_type = ftype;
return funaddr + gdbarch_deprecated_function_start_offset (gdbarch);
}
}
{
- 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 ());
}
}
/* If using a structure return, this is the structure's address. */
CORE_ADDR struct_addr;
-
- /* Whether stack temporaries are enabled. */
- int stack_temporaries_enabled;
};
/* Extract the called function's return value. */
get_call_return_value (struct call_return_meta_info *ri)
{
struct value *retval = NULL;
- int 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;
}
void *dummy_dtor_data)
{
CORE_ADDR sp;
- struct type *values_type, *target_values_type;
+ struct type *target_values_type;
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;
- struct infcall_suspend_state *caller_state;
- CORE_ADDR funaddr;
CORE_ADDR real_pc;
- struct type *ftype = check_typedef (value_type (function));
CORE_ADDR bp_addr;
struct frame_id dummy_id;
struct frame_info *frame;
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);
-
- if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
- ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
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);
}
}
- funaddr = find_function_addr (function, &values_type);
+ 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)
target_values_type = values_type;
}
- observer_notify_inferior_call_pre (inferior_ptid, funaddr);
+ gdb::observers::inferior_call_pre.notify (inferior_ptid, funaddr);
/* Determine the location of the breakpoint (and possibly other
stuff) that the called function will return to. The SPARC, for a
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;
+ for (int 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)
+ /* 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
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. */
struct_return || hidden_first_param_p,
struct_addr);
- e = run_inferior_call (sm, tp, real_pc);
+ e = run_inferior_call (sm, call_thread.get (), real_pc);
- observer_notify_inferior_call_post (call_thread_ptid, funaddr);
+ 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."