2007-11-07 Markus Deuling <deuling@de.ibm.com>
[deliverable/binutils-gdb.git] / gdb / infcall.c
index 5eb9ca3f942e10ad52e6ee8725229f65320bad3d..99d3cccd3c4e3959c9080a9262926726583a063d 100644 (file)
@@ -8,7 +8,7 @@
 
    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 <http://www.gnu.org/licenses/>.  */
 
 #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,
+                                                           &current_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
@@ -246,10 +260,11 @@ breakpoint_auto_delete_contents (void *arg)
 
 static CORE_ADDR
 generic_push_dummy_code (struct gdbarch *gdbarch,
-                        CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
+                        CORE_ADDR sp, CORE_ADDR funaddr,
                         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.  */
@@ -285,17 +300,20 @@ generic_push_dummy_code (struct gdbarch *gdbarch,
 
 static CORE_ADDR
 push_dummy_code (struct gdbarch *gdbarch,
-                CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
+                CORE_ADDR sp, CORE_ADDR funaddr,
                 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);
+    return gdbarch_push_dummy_code (gdbarch, sp, funaddr,
+                                   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);
+    return generic_push_dummy_code (gdbarch, sp, funaddr,
+                                   args, nargs, value_type, real_pc, bp_addr,
+                                   regcache);
 }
 
 /* All this stuff with a dummy frame may seem unnecessarily complicated
@@ -321,21 +339,21 @@ 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;
   struct inferior_status *inf_status;
   struct cleanup *inf_status_cleanup;
   CORE_ADDR funaddr;
-  int using_gcc;               /* Set to version of gcc in use, or zero if not gcc */
   CORE_ADDR real_pc;
   struct type *ftype = check_typedef (value_type (function));
   CORE_ADDR bp_addr;
   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));
@@ -377,7 +395,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 +423,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!
@@ -434,16 +454,30 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
   funaddr = find_function_addr (function, &values_type);
   CHECK_TYPEDEF (values_type);
 
-  {
-    struct block *b = block_for_pc (funaddr);
-    /* If compiled without -g, assume GCC 2.  */
-    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);
+      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 +488,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);
+                               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);
+                               args, nargs, target_values_type,
+                               &real_pc, &bp_addr, get_current_regcache ());
        }
       break;
     case AT_ENTRY_POINT:
@@ -537,111 +571,22 @@ 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);
 
-       /* 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
-          and not a pointer to function variable.  In aCC compiled
-          code, the calls through pointers to functions (in the body
-          of the function called by hand) are made via
-          $$dyncall_external which requires some registers setting,
-          this is taken care of if we call via a function pointer
-          variable, but not via a function address.  In cc this is
-          not a problem. */
-
-       if (using_gcc == 0)
-         {
-           if (param_type != NULL && TYPE_CODE (ftype) != TYPE_CODE_METHOD)
-             {
-               /* if this parameter is a pointer to function.  */
-               if (TYPE_CODE (param_type) == TYPE_CODE_PTR)
-                 if (TYPE_CODE (TYPE_TARGET_TYPE (param_type)) == TYPE_CODE_FUNC)
-                   /* elz: FIXME here should go the test about the
-                      compiler used to compile the target. We want to
-                      issue the error message only if the compiler
-                      used was HP's aCC.  If we used HP's cc, then
-                      there is no problem and no need to return at
-                      this point.  */
-                   /* Go see if the actual parameter is a variable of
-                      type pointer to function or just a function.  */
-                   if (VALUE_LVAL (args[i]) == not_lval)
-                     {
-                       char *arg_name;
-                       /* NOTE: cagney/2005-01-02: THIS IS BOGUS.  */
-                       if (find_pc_partial_function ((CORE_ADDR) value_contents (args[i])[0], &arg_name, NULL, NULL))
-                         error (_("\
-You cannot use function <%s> as argument. \n\
-You must use a pointer to function type variable. Command ignored."), arg_name);
-                     }
-             }
-         }
+       if (param_type != NULL && language_pass_by_reference (param_type))
+         args[i] = value_addr (args[i]);
       }
   }
 
-  if (DEPRECATED_REG_STRUCT_HAS_ADDR_P ())
-    {
-      int i;
-      /* This is a machine like the sparc, where we may need to pass a
-        pointer to the structure, not the structure itself.  */
-      for (i = nargs - 1; i >= 0; i--)
-       {
-         struct type *arg_type = check_typedef (value_type (args[i]));
-         if ((TYPE_CODE (arg_type) == TYPE_CODE_STRUCT
-              || TYPE_CODE (arg_type) == TYPE_CODE_UNION
-              || TYPE_CODE (arg_type) == TYPE_CODE_ARRAY
-              || TYPE_CODE (arg_type) == TYPE_CODE_STRING
-              || TYPE_CODE (arg_type) == TYPE_CODE_BITSTRING
-              || TYPE_CODE (arg_type) == TYPE_CODE_SET
-              || (TYPE_CODE (arg_type) == TYPE_CODE_FLT
-                  && TYPE_LENGTH (arg_type) > 8)
-              )
-             && DEPRECATED_REG_STRUCT_HAS_ADDR (using_gcc, arg_type))
-           {
-             CORE_ADDR addr;
-             int len;          /*  = TYPE_LENGTH (arg_type); */
-             int aligned_len;
-             arg_type = check_typedef (value_enclosing_type (args[i]));
-             len = TYPE_LENGTH (arg_type);
-
-             aligned_len = len;
-             if (INNER_THAN (1, 2))
-               {
-                 /* stack grows downward */
-                 sp -= aligned_len;
-                 /* ... so the address of the thing we push is the
-                    stack pointer after we push it.  */
-                 addr = sp;
-               }
-             else
-               {
-                 /* The stack grows up, so the address of the thing
-                    we push is the stack pointer before we push it.  */
-                 addr = sp;
-                 sp += aligned_len;
-               }
-             /* Push the structure.  */
-             write_memory (addr, value_contents_all (args[i]), len);
-             /* The value we're going to pass is the address of the
-                thing we just pushed.  */
-             /*args[i] = value_from_longest (lookup_pointer_type (values_type),
-               (LONGEST) addr); */
-             args[i] = value_from_pointer (lookup_pointer_type (arg_type),
-                                           addr);
-           }
-       }
-    }
-
-
   /* Reserve space for the return structure to be written on the
      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 +608,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 +824,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 +836,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:
This page took 0.046341 seconds and 4 git commands to generate.