X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfcall.c;h=3012d7f45d9e19c0903e35be1681f4b2934a1968;hb=f2476b303ae3876c0be48ffb91d1032299b7f8b8;hp=64772d7590fdcdf61d5600eab1dc2fd1d0ac32c9;hpb=0d5de0100fd9c669790851af4f9f50704a24b453;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infcall.c b/gdb/infcall.c index 64772d7590..3012d7f45d 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -1,14 +1,14 @@ /* 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, @@ -17,9 +17,7 @@ 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 . */ #include "defs.h" #include "breakpoint.h" @@ -222,8 +220,24 @@ find_function_addr (struct value *function, struct type **retval_type) 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; } @@ -232,7 +246,7 @@ find_function_addr (struct value *function, struct type **retval_type) 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 @@ -249,7 +263,8 @@ generic_push_dummy_code (struct gdbarch *gdbarch, 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. */ @@ -288,14 +303,17 @@ push_dummy_code (struct gdbarch *gdbarch, 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 @@ -321,8 +339,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) { 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; @@ -336,6 +354,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) 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)); @@ -368,7 +387,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) /* 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); @@ -377,7 +396,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) 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); @@ -405,15 +424,17 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) 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! @@ -440,10 +461,30 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) 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 @@ -454,24 +495,24 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) /* 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: @@ -537,9 +578,12 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) 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 @@ -580,7 +624,7 @@ You must use a pointer to function type variable. Command ignored."), arg_name); } } - 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 @@ -597,7 +641,8 @@ You must use a pointer to function type variable. Command ignored."), arg_name); || (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); */ @@ -606,7 +651,7 @@ You must use a pointer to function type variable. Command ignored."), arg_name); 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; @@ -638,10 +683,10 @@ You must use a pointer to function type variable. Command ignored."), arg_name); 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. */ @@ -663,12 +708,30 @@ You must use a pointer to function type variable. Command ignored."), arg_name); } } + 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 @@ -861,7 +924,9 @@ the function call)."), name); { 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. */ @@ -871,7 +936,7 @@ the function call)."), name); { 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: