OSDN Git Service

* alpha-tdep.c (alpha_push_dummy_call): Transmography from
authorRichard Henderson <rth@redhat.com>
Sun, 1 Jun 2003 16:02:50 +0000 (16:02 +0000)
committerRichard Henderson <rth@redhat.com>
Sun, 1 Jun 2003 16:02:50 +0000 (16:02 +0000)
        alpha_push_arguments.  Don't dump argument register data to
        the target stack.  Fix float and 128-bit long double semantics.
        Store $t12 and $ra as specified by the ABI.  Use regcache everywhere.
        (alpha_fix_call_dummy): Remove.
        (alpha_call_dummy_words): Remove.
        (alpha_gdbarch_init): Kill deprecated call hooks; add push_dummy_call.

gdb/ChangeLog
gdb/alpha-tdep.c

index 78ab5b1..db2244b 100644 (file)
@@ -1,5 +1,15 @@
 2003-06-01  Richard Henderson  <rth@redhat.com>
 
+        * alpha-tdep.c (alpha_push_dummy_call): Transmography from
+        alpha_push_arguments.  Don't dump argument register data to
+        the target stack.  Fix float and 128-bit long double semantics.
+        Store $t12 and $ra as specified by the ABI.  Use regcache everywhere.
+        (alpha_fix_call_dummy): Remove.
+        (alpha_call_dummy_words): Remove.
+        (alpha_gdbarch_init): Kill deprecated call hooks; add push_dummy_call.
+
+2003-06-01  Richard Henderson  <rth@redhat.com>
+
        * alpha-linux-tdep.c (alpha_linux_init_abi): Install dwarf2 unwinder.
 
 2003-06-01  Andrew Cagney  <cagney@redhat.com>
index cd29c95..fd8c88e 100644 (file)
@@ -173,38 +173,50 @@ alpha_register_convert_to_raw (struct type *valtype, int regnum,
 
 \f
 /* The alpha passes the first six arguments in the registers, the rest on
-   the stack. The register arguments are eventually transferred to the
-   argument transfer area immediately below the stack by the called function
-   anyway. So we `push' at least six arguments on the stack, `reload' the
-   argument registers and then adjust the stack pointer to point past the
-   sixth argument. This algorithm simplifies the passing of a large struct
-   which extends from the registers to the stack.
+   the stack.  The register arguments are stored in ARG_REG_BUFFER, and
+   then moved into the register file; this simplifies the passing of a
+   large struct which extends from the registers to the stack, plus avoids
+   three ptrace invocations per word.
+
+   We don't bother tracking which register values should go in integer
+   regs or fp regs; we load the same values into both.
+
    If the called function is returning a structure, the address of the
    structure to be returned is passed as a hidden first argument.  */
 
 static CORE_ADDR
-alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
-                     int struct_return, CORE_ADDR struct_addr)
+alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+                      struct regcache *regcache, CORE_ADDR bp_addr,
+                      int nargs, struct value **args, CORE_ADDR sp,
+                      int struct_return, CORE_ADDR struct_addr)
 {
   int i;
   int accumulate_size = struct_return ? 8 : 0;
-  int arg_regs_size = ALPHA_NUM_ARG_REGS * 8;
   struct alpha_arg
     {
       char *contents;
       int len;
       int offset;
     };
-  struct alpha_arg *alpha_args =
-  (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
+  struct alpha_arg *alpha_args
+    = (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
   register struct alpha_arg *m_arg;
-  char raw_buffer[ALPHA_REGISTER_BYTES];
+  char arg_reg_buffer[ALPHA_REGISTER_SIZE * ALPHA_NUM_ARG_REGS];
   int required_arg_regs;
 
+  /* The ABI places the address of the called function in T12.  */
+  regcache_cooked_write_signed (regcache, ALPHA_T12_REGNUM, func_addr);
+
+  /* Set the return address register to point to the entry point
+     of the program, where a breakpoint lies in wait.  */
+  regcache_cooked_write_signed (regcache, ALPHA_RA_REGNUM, bp_addr);
+
+  /* Lay out the arguments in memory.  */
   for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
     {
       struct value *arg = args[i];
       struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+
       /* Cast argument to long if necessary as the compiler does it too.  */
       switch (TYPE_CODE (arg_type))
        {
@@ -219,6 +231,30 @@ alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
              arg = value_cast (arg_type, arg);
            }
          break;
+       case TYPE_CODE_FLT:
+         /* "float" arguments loaded in registers must be passed in
+            register format, aka "double".  */
+         if (accumulate_size < sizeof (arg_reg_buffer)
+             && TYPE_LENGTH (arg_type) == 4)
+           {
+             arg_type = builtin_type_double;
+             arg = value_cast (arg_type, arg);
+           }
+         /* Tru64 5.1 has a 128-bit long double, and passes this by
+            invisible reference.  No one else uses this data type.  */
+         else if (TYPE_LENGTH (arg_type) == 16)
+           {
+             /* Allocate aligned storage.  */
+             sp = (sp & -16) - 16;
+
+             /* Write the real data into the stack.  */
+             write_memory (sp, VALUE_CONTENTS (arg), 16);
+
+             /* Construct the indirection.  */
+             arg_type = lookup_pointer_type (arg_type);
+             arg = value_from_pointer (arg_type, sp);
+           }
+         break;
        default:
          break;
        }
@@ -235,33 +271,58 @@ alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
     required_arg_regs = ALPHA_NUM_ARG_REGS;
 
   /* Make room for the arguments on the stack.  */
-  if (accumulate_size < arg_regs_size)
-    accumulate_size = arg_regs_size;
+  if (accumulate_size < sizeof(arg_reg_buffer))
+    accumulate_size = 0;
+  else
+    accumulate_size -= sizeof(arg_reg_buffer);
   sp -= accumulate_size;
 
-  /* Keep sp aligned to a multiple of 16 as the compiler does it too.  */
+  /* Keep sp aligned to a multiple of 16 as the ABI requires.  */
   sp &= ~15;
 
   /* `Push' arguments on the stack.  */
   for (i = nargs; m_arg--, --i >= 0;)
-    write_memory (sp + m_arg->offset, m_arg->contents, m_arg->len);
-  if (struct_return)
     {
-      store_unsigned_integer (raw_buffer, ALPHA_REGISTER_BYTES, struct_addr);
-      write_memory (sp, raw_buffer, ALPHA_REGISTER_BYTES);
+      char *contents = m_arg->contents;
+      int offset = m_arg->offset;
+      int len = m_arg->len;
+
+      /* Copy the bytes destined for registers into arg_reg_buffer.  */
+      if (offset < sizeof(arg_reg_buffer))
+       {
+         if (offset + len <= sizeof(arg_reg_buffer))
+           {
+             memcpy (arg_reg_buffer + offset, contents, len);
+             continue;
+           }
+         else
+           {
+             int tlen = sizeof(arg_reg_buffer) - offset;
+             memcpy (arg_reg_buffer + offset, contents, tlen);
+             offset += tlen;
+             contents += tlen;
+             len -= tlen;
+           }
+       }
+
+      /* Everything else goes to the stack.  */
+      write_memory (sp + offset - sizeof(arg_reg_buffer), contents, len);
     }
+  if (struct_return)
+    store_unsigned_integer (arg_reg_buffer, ALPHA_REGISTER_SIZE, struct_addr);
 
   /* Load the argument registers.  */
   for (i = 0; i < required_arg_regs; i++)
     {
       LONGEST val;
 
-      val = read_memory_integer (sp + i * 8, ALPHA_REGISTER_BYTES);
-      write_register (ALPHA_A0_REGNUM + i, val);
-      write_register (ALPHA_FPA0_REGNUM + i, val);
+      val = extract_unsigned_integer (arg_reg_buffer + i*ALPHA_REGISTER_SIZE,
+                                     ALPHA_REGISTER_SIZE);
+      regcache_cooked_write_signed (regcache, ALPHA_A0_REGNUM + i, val);
+      regcache_cooked_write_signed (regcache, ALPHA_FPA0_REGNUM + i, val);
     }
 
-  return sp + arg_regs_size;
+  return sp;
 }
 
 /* Given a return value in `regbuf' with a type `valtype', 
@@ -438,28 +499,6 @@ alpha_skip_prologue (CORE_ADDR pc)
 }
 
 \f
-/* Construct an inferior call to FUN.  For Alpha this is as simple as
-   initializing the RA and T12 registers; everything else is set up by
-   generic code.  */
-
-static void
-alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
-                      struct value **args, struct type *type, int gcc_p)
-{
-  CORE_ADDR bp_address = CALL_DUMMY_ADDRESS ();
-
-  if (bp_address == 0)
-    error ("no place to put call");
-  write_register (ALPHA_RA_REGNUM, bp_address);
-  write_register (ALPHA_T12_REGNUM, fun);
-}
-
-/* On the Alpha, the call dummy code is never copied to user space
-   (see alpha_fix_call_dummy() above).  The contents of this do not
-   matter.  */
-LONGEST alpha_call_dummy_words[] = { 0 };
-
-\f
 /* Figure out where the longjmp will land.
    We expect the first arg to be a pointer to the jmp_buf structure from
    which we extract the PC (JB_PC) that we will land at.  The PC is copied
@@ -1242,11 +1281,7 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                                            alpha_extract_struct_value_address);
 
   /* Settings for calling functions in the inferior.  */
-  set_gdbarch_deprecated_push_arguments (gdbarch, alpha_push_arguments);
-  set_gdbarch_deprecated_call_dummy_words (gdbarch, alpha_call_dummy_words);
-  set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
-  set_gdbarch_deprecated_pc_in_call_dummy (gdbarch, deprecated_pc_in_call_dummy_at_entry_point);
-  set_gdbarch_deprecated_fix_call_dummy (gdbarch, alpha_fix_call_dummy);
+  set_gdbarch_push_dummy_call (gdbarch, alpha_push_dummy_call);
 
   /* Methods for saving / extracting a dummy frame's ID.  */
   set_gdbarch_unwind_dummy_id (gdbarch, alpha_unwind_dummy_id);