2007-11-07 Markus Deuling <deuling@de.ibm.com>
[deliverable/binutils-gdb.git] / gdb / infcall.c
index b603da8b2dda104893eb2fa22976a3f3ea0bc9c9..99d3cccd3c4e3959c9080a9262926726583a063d 100644 (file)
@@ -260,7 +260,7 @@ 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,
@@ -300,18 +300,18 @@ 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,
                 struct regcache *regcache)
 {
   if (gdbarch_push_dummy_code_p (gdbarch))
-    return gdbarch_push_dummy_code (gdbarch, sp, funaddr, using_gcc,
+    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,
+    return generic_push_dummy_code (gdbarch, sp, funaddr,
                                    args, nargs, value_type, real_pc, bp_addr,
                                    regcache);
 }
@@ -339,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));
@@ -454,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
@@ -482,7 +496,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
       if (gdbarch_inner_than (current_gdbarch, 1, 2))
        {
          sp = push_dummy_code (current_gdbarch, sp, funaddr,
-                               using_gcc, args, nargs, values_type,
+                               args, nargs, target_values_type,
                                &real_pc, &bp_addr, get_current_regcache ());
          dummy_addr = sp;
        }
@@ -490,7 +504,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
        {
          dummy_addr = sp;
          sp = push_dummy_code (current_gdbarch, sp, funaddr,
-                               using_gcc, args, nargs, values_type,
+                               args, nargs, target_values_type,
                                &real_pc, &bp_addr, get_current_regcache ());
        }
       break;
@@ -557,109 +571,19 @@ 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 (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
-        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)
-              )
-             && gdbarch_deprecated_reg_struct_has_addr
-                  (current_gdbarch, 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 (gdbarch_inner_than (current_gdbarch, 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 (gdbarch_inner_than (current_gdbarch, 1, 2))
@@ -684,6 +608,22 @@ 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.  */
@@ -691,6 +631,8 @@ You must use a pointer to function type variable. Command ignored."), arg_name);
                                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
      ID so that the breakpoint code can correctly re-identify the
@@ -882,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.  */
@@ -892,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.028145 seconds and 4 git commands to generate.