/* 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
+ Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "breakpoint.h"
if (TYPE_LENGTH (ftype) == 1)
funaddr = value_as_address (value_addr (function));
else
- /* Handle integer used as address of a function. */
- funaddr = (CORE_ADDR) value_as_long (function);
+ {
+ /* Handle function descriptors lacking debug info. */
+ int found_descriptor = 0;
+ if (VALUE_LVAL (function) == lval_memory)
+ {
+ CORE_ADDR nfunaddr;
+ funaddr = value_as_address (value_addr (function));
+ nfunaddr = funaddr;
+ funaddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ funaddr,
+ ¤t_target);
+ if (funaddr != nfunaddr)
+ found_descriptor = 1;
+ }
+ if (!found_descriptor)
+ /* Handle integer used as address of a function. */
+ funaddr = (CORE_ADDR) value_as_long (function);
+ }
value_type = builtin_type_int;
}
if (retval_type != NULL)
*retval_type = value_type;
- return funaddr + DEPRECATED_FUNCTION_START_OFFSET;
+ return funaddr + gdbarch_deprecated_function_start_offset (current_gdbarch);
}
/* Call breakpoint_auto_delete on the current contents of the bpstat
CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
struct value **args, int nargs,
struct type *value_type,
- CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+ struct regcache *regcache)
{
/* Something here to findout the size of a breakpoint and then
allocate space for it on the stack. */
CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
struct value **args, int nargs,
struct type *value_type,
- CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+ struct regcache *regcache)
{
if (gdbarch_push_dummy_code_p (gdbarch))
return gdbarch_push_dummy_code (gdbarch, sp, funaddr, using_gcc,
- args, nargs, value_type, real_pc, bp_addr);
+ args, nargs, value_type, real_pc, bp_addr,
+ regcache);
else
return generic_push_dummy_code (gdbarch, sp, funaddr, using_gcc,
- args, nargs, value_type, real_pc, bp_addr);
+ args, nargs, value_type, real_pc, bp_addr,
+ regcache);
}
/* All this stuff with a dummy frame may seem unnecessarily complicated
{
CORE_ADDR sp;
CORE_ADDR dummy_addr;
- struct type *values_type;
- unsigned char struct_return;
+ struct type *values_type, *target_values_type;
+ unsigned char struct_return = 0, lang_struct_return = 0;
CORE_ADDR struct_addr = 0;
struct regcache *retbuf;
struct cleanup *retbuf_cleanup;
struct regcache *caller_regcache;
struct cleanup *caller_regcache_cleanup;
struct frame_id dummy_id;
+ struct cleanup *args_cleanup;
if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
/* Ensure that the initial SP is correctly aligned. */
{
- CORE_ADDR old_sp = read_sp ();
+ CORE_ADDR old_sp = get_frame_sp (get_current_frame ());
if (gdbarch_frame_align_p (current_gdbarch))
{
sp = gdbarch_frame_align (current_gdbarch, old_sp);
address. AMD64 called that region the "red zone". Skip at
least the "red zone" size before allocating any space on
the stack. */
- if (INNER_THAN (1, 2))
+ if (gdbarch_inner_than (current_gdbarch, 1, 2))
sp -= gdbarch_frame_red_zone_size (current_gdbarch);
else
sp += gdbarch_frame_red_zone_size (current_gdbarch);
to pay :-). */
if (sp == old_sp)
{
- if (INNER_THAN (1, 2))
+ if (gdbarch_inner_than (current_gdbarch, 1, 2))
/* Stack grows down. */
sp = gdbarch_frame_align (current_gdbarch, old_sp - 1);
else
/* Stack grows up. */
sp = gdbarch_frame_align (current_gdbarch, old_sp + 1);
}
- gdb_assert ((INNER_THAN (1, 2) && sp <= old_sp)
- || (INNER_THAN (2, 1) && sp >= old_sp));
+ gdb_assert ((gdbarch_inner_than (current_gdbarch, 1, 2)
+ && sp <= old_sp)
+ || (gdbarch_inner_than (current_gdbarch, 2, 1)
+ && sp >= old_sp));
}
else
/* FIXME: cagney/2002-09-18: Hey, you loose!
using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
}
- /* Are we returning a value using a structure return or a normal
- value return? */
+ /* 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. */
+
+ if (language_pass_by_reference (values_type))
+ {
+ lang_struct_return = 1;
- struct_return = using_struct_return (values_type, using_gcc);
+ /* Tell the target specific argument pushing routine not to
+ expect a value. */
+ target_values_type = builtin_type_void;
+ }
+ else
+ {
+ struct_return = using_struct_return (values_type, using_gcc);
+ target_values_type = values_type;
+ }
/* Determine the location of the breakpoint (and possibly other
stuff) that the called function will return to. The SPARC, for a
/* The actual breakpoint (at BP_ADDR) is inserted separatly so there
is no need to write that out. */
- switch (CALL_DUMMY_LOCATION)
+ switch (gdbarch_call_dummy_location (current_gdbarch))
{
case ON_STACK:
/* "dummy_addr" is here just to keep old targets happy. New
targets return that same information via "sp" and "bp_addr". */
- if (INNER_THAN (1, 2))
+ if (gdbarch_inner_than (current_gdbarch, 1, 2))
{
sp = push_dummy_code (current_gdbarch, sp, funaddr,
- using_gcc, args, nargs, values_type,
- &real_pc, &bp_addr);
+ using_gcc, args, nargs, target_values_type,
+ &real_pc, &bp_addr, get_current_regcache ());
dummy_addr = sp;
}
else
{
dummy_addr = sp;
sp = push_dummy_code (current_gdbarch, sp, funaddr,
- using_gcc, args, nargs, values_type,
- &real_pc, &bp_addr);
+ using_gcc, args, nargs, target_values_type,
+ &real_pc, &bp_addr, get_current_regcache ());
}
break;
case AT_ENTRY_POINT:
param_type = TYPE_FIELD_TYPE (ftype, i);
else
param_type = NULL;
-
+
args[i] = value_arg_coerce (args[i], param_type, prototyped);
+ if (param_type != NULL && language_pass_by_reference (param_type))
+ args[i] = value_addr (args[i]);
+
/* elz: this code is to handle the case in which the function
to be called has a pointer to function as parameter and the
corresponding actual argument is the address of a function
}
}
- if (DEPRECATED_REG_STRUCT_HAS_ADDR_P ())
+ if (gdbarch_deprecated_reg_struct_has_addr_p (current_gdbarch))
{
int i;
/* This is a machine like the sparc, where we may need to pass a
|| (TYPE_CODE (arg_type) == TYPE_CODE_FLT
&& TYPE_LENGTH (arg_type) > 8)
)
- && DEPRECATED_REG_STRUCT_HAS_ADDR (using_gcc, arg_type))
+ && gdbarch_deprecated_reg_struct_has_addr
+ (current_gdbarch, using_gcc, arg_type))
{
CORE_ADDR addr;
int len; /* = TYPE_LENGTH (arg_type); */
len = TYPE_LENGTH (arg_type);
aligned_len = len;
- if (INNER_THAN (1, 2))
+ if (gdbarch_inner_than (current_gdbarch, 1, 2))
{
/* stack grows downward */
sp -= aligned_len;
stack, if necessary. Make certain that the value is correctly
aligned. */
- if (struct_return)
+ if (struct_return || lang_struct_return)
{
int len = TYPE_LENGTH (values_type);
- if (INNER_THAN (1, 2))
+ if (gdbarch_inner_than (current_gdbarch, 1, 2))
{
/* Stack grows downward. Align STRUCT_ADDR and SP after
making space for the return value. */
}
}
+ if (lang_struct_return)
+ {
+ struct value **new_args;
+
+ /* Add the new argument to the front of the argument list. */
+ new_args = xmalloc (sizeof (struct value *) * (nargs + 1));
+ new_args[0] = value_from_pointer (lookup_pointer_type (values_type),
+ struct_addr);
+ memcpy (&new_args[1], &args[0], sizeof (struct value *) * nargs);
+ args = new_args;
+ nargs++;
+ args_cleanup = make_cleanup (xfree, args);
+ }
+ else
+ args_cleanup = make_cleanup (null_cleanup, NULL);
+
/* 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 (current_gdbarch, function, current_regcache,
- bp_addr, nargs, args, sp, struct_return,
- struct_addr);
+ sp = gdbarch_push_dummy_call (current_gdbarch, function,
+ get_current_regcache (), bp_addr, nargs, args,
+ sp, struct_return, struct_addr);
+
+ do_cleanups (args_cleanup);
/* 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
{
struct value *retval = NULL;
- if (TYPE_CODE (values_type) == TYPE_CODE_VOID)
+ if (lang_struct_return)
+ retval = value_at (values_type, struct_addr);
+ else if (TYPE_CODE (target_values_type) == TYPE_CODE_VOID)
{
/* If the function returns void, don't bother fetching the
return value. */
{
struct gdbarch *arch = current_gdbarch;
- switch (gdbarch_return_value (arch, values_type, NULL, NULL, NULL))
+ switch (gdbarch_return_value (arch, target_values_type, NULL, NULL, NULL))
{
case RETURN_VALUE_REGISTER_CONVENTION:
case RETURN_VALUE_ABI_RETURNS_ADDRESS: