2002-09-18 Andrew Cagney <ac131313@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Wed, 18 Sep 2002 15:37:18 +0000 (15:37 +0000)
committerAndrew Cagney <cagney@redhat.com>
Wed, 18 Sep 2002 15:37:18 +0000 (15:37 +0000)
* valops.c (hand_function_call): Align the initial stack pointer
and STRUCT_ADDR using frame_align.  When STRUCT_RETURN and
FRAME_ALIGN_P, use STRUCT_ADDR to obtain the called function's
return value.
* mips-tdep.c (mips_frame_align): New function.
(mips_gdbarch_init): Set frame_align.
* gdbarch.sh (FRAME_ALIGN): New method.
* gdbarch.h, gdbarch.c: Re-generate.

gdb/ChangeLog
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/mips-tdep.c
gdb/valops.c

index b7bc52c1cb624c9fa7c693a286da49dc80453145..441bc14c03bf787e88b812c7d5a5b1f1404ff98b 100644 (file)
@@ -1,3 +1,14 @@
+2002-09-18  Andrew Cagney  <ac131313@redhat.com>
+
+       * valops.c (hand_function_call): Align the initial stack pointer
+       and STRUCT_ADDR using frame_align.  When STRUCT_RETURN and
+       FRAME_ALIGN_P, use STRUCT_ADDR to obtain the called function's
+       return value.
+       * mips-tdep.c (mips_frame_align): New function.
+       (mips_gdbarch_init): Set frame_align.
+       * gdbarch.sh (FRAME_ALIGN): New method.
+       * gdbarch.h, gdbarch.c: Re-generate.
+
 2002-09-18  Michal Ludvig  <mludvig@suse.cz>
 
        * x86-64-linux-nat.c (x86_64_regmap): Added CS and SS
index 5766751591160772ce3c2147e852fd343d6f5bd9..bc27aaeef6a7f6c2c377c09703829ba8b588df00 100644 (file)
@@ -244,6 +244,7 @@ struct gdbarch
   gdbarch_saved_pc_after_call_ftype *saved_pc_after_call;
   gdbarch_frame_num_args_ftype *frame_num_args;
   gdbarch_stack_align_ftype *stack_align;
+  gdbarch_frame_align_ftype *frame_align;
   int extra_stack_alignment_needed;
   gdbarch_reg_struct_has_addr_ftype *reg_struct_has_addr;
   gdbarch_save_dummy_frame_tos_ftype *save_dummy_frame_tos;
@@ -419,6 +420,7 @@ struct gdbarch startup_gdbarch =
   0,
   0,
   0,
+  0,
   generic_in_function_epilogue_p,
   construct_inferior_arguments,
   0,
@@ -775,6 +777,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
       && (gdbarch->frame_num_args == 0))
     fprintf_unfiltered (log, "\n\tframe_num_args");
   /* Skip verify of stack_align, has predicate */
+  /* Skip verify of frame_align, has predicate */
   /* Skip verify of extra_stack_alignment_needed, invalid_p == 0 */
   /* Skip verify of reg_struct_has_addr, has predicate */
   /* Skip verify of save_dummy_frame_tos, has predicate */
@@ -825,6 +828,10 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: GDB_MULTI_ARCH = %d\n",
                       GDB_MULTI_ARCH);
+  if (GDB_MULTI_ARCH)
+    fprintf_unfiltered (file,
+                        "gdbarch_dump: frame_align = 0x%08lx\n",
+                        (long) current_gdbarch->frame_align);
   if (GDB_MULTI_ARCH)
     fprintf_unfiltered (file,
                         "gdbarch_dump: in_function_epilogue_p = 0x%08lx\n",
@@ -4509,6 +4516,32 @@ set_gdbarch_stack_align (struct gdbarch *gdbarch,
   gdbarch->stack_align = stack_align;
 }
 
+int
+gdbarch_frame_align_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->frame_align != 0;
+}
+
+CORE_ADDR
+gdbarch_frame_align (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+  gdb_assert (gdbarch != NULL);
+  if (gdbarch->frame_align == 0)
+    internal_error (__FILE__, __LINE__,
+                    "gdbarch: gdbarch_frame_align invalid");
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_frame_align called\n");
+  return gdbarch->frame_align (gdbarch, address);
+}
+
+void
+set_gdbarch_frame_align (struct gdbarch *gdbarch,
+                         gdbarch_frame_align_ftype frame_align)
+{
+  gdbarch->frame_align = frame_align;
+}
+
 int
 gdbarch_extra_stack_alignment_needed (struct gdbarch *gdbarch)
 {
index 15bed4ca0e7c8844cfc6d50d7250c903e218238a..2f26cba9a13008ff44c72a29a681a7e685e5627d 100644 (file)
@@ -2014,6 +2014,12 @@ extern void set_gdbarch_stack_align (struct gdbarch *gdbarch, gdbarch_stack_alig
 #endif
 #endif
 
+extern int gdbarch_frame_align_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_frame_align_ftype) (struct gdbarch *gdbarch, CORE_ADDR address);
+extern CORE_ADDR gdbarch_frame_align (struct gdbarch *gdbarch, CORE_ADDR address);
+extern void set_gdbarch_frame_align (struct gdbarch *gdbarch, gdbarch_frame_align_ftype *frame_align);
+
 /* Default (value) for non- multi-arch platforms. */
 #if (!GDB_MULTI_ARCH) && !defined (EXTRA_STACK_ALIGNMENT_NEEDED)
 #define EXTRA_STACK_ALIGNMENT_NEEDED (1)
index 1058f7c6b5eb80485d7dc174b92366cf3dc77a9f..0ee74df6f446d81c47d40da185b052db8ba9035c 100755 (executable)
@@ -572,6 +572,7 @@ f:2:SAVED_PC_AFTER_CALL:CORE_ADDR:saved_pc_after_call:struct frame_info *frame:f
 f:2:FRAME_NUM_ARGS:int:frame_num_args:struct frame_info *frame:frame::0:0
 #
 F:2:STACK_ALIGN:CORE_ADDR:stack_align:CORE_ADDR sp:sp::0:0
+M:::CORE_ADDR:frame_align:CORE_ADDR address:address
 v:2:EXTRA_STACK_ALIGNMENT_NEEDED:int:extra_stack_alignment_needed::::0:1::0:::
 F:2:REG_STRUCT_HAS_ADDR:int:reg_struct_has_addr:int gcc_p, struct type *type:gcc_p, type::0:0
 F:2:SAVE_DUMMY_FRAME_TOS:void:save_dummy_frame_tos:CORE_ADDR sp:sp::0:0
index 79b189cb187d832df09f1ec04627a154e5a8e4f0..f54f19c2ad702be0bbd7679550925b9476ff1698 100644 (file)
@@ -2584,6 +2584,14 @@ mips_type_needs_double_align (struct type *type)
 #define ROUND_DOWN(n,a) ((n) & ~((a)-1))
 #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
 
+/* Adjust the address downward (direction of stack growth) so that it
+   is correctly aligned for a new stack frame.  */
+static CORE_ADDR
+mips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return ROUND_DOWN (addr, 16);
+}
+
 static CORE_ADDR
 mips_eabi_push_arguments (int nargs,
                          struct value **args,
@@ -5963,6 +5971,7 @@ mips_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_call_dummy_words (gdbarch, mips_call_dummy_words);
   set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (mips_call_dummy_words));
   set_gdbarch_push_return_address (gdbarch, mips_push_return_address);
+  set_gdbarch_frame_align (gdbarch, mips_frame_align);
   set_gdbarch_register_convertible (gdbarch, mips_register_convertible);
   set_gdbarch_register_convert_to_virtual (gdbarch, 
                                           mips_register_convert_to_virtual);
index 2e61e8883a37807f15108b37107a67502ba2ac87..eaf429531082beeebfc4aa7a6a60aafdfec1a4da 100644 (file)
@@ -1351,7 +1351,55 @@ hand_function_call (struct value *function, int nargs, struct value **args)
      they are saved on the stack in the inferior.  */
   PUSH_DUMMY_FRAME;
 
-  old_sp = sp = read_sp ();
+  old_sp = read_sp ();
+
+  /* Ensure that the initial SP is correctly aligned.  */
+  if (gdbarch_frame_align_p (current_gdbarch))
+    {
+      /* NOTE: cagney/2002-09-18:
+
+        On a RISC architecture, a void parameterless generic dummy
+        frame (i.e., no parameters, no result) typically does not
+        need to push anything the stack and hence can leave SP and
+        FP.  Similarly, a framelss (possibly leaf) function does not
+        push anything on the stack and, hence, that too can leave FP
+        and SP unchanged.  As a consequence, a sequence of void
+        parameterless generic dummy frame calls to frameless
+        functions will create a sequence of effectively identical
+        frames (SP, FP and TOS and PC the same).  This, not
+        suprisingly, results in what appears to be a stack in an
+        infinite loop --- when GDB tries to find a generic dummy
+        frame on the internal dummy frame stack, it will always find
+        the first one.
+
+        To avoid this problem, the code below always grows the stack.
+        That way, two dummy frames can never be identical.  It does
+        burn a few bytes of stack but that is a small price to pay
+        :-).  */
+      sp = gdbarch_frame_align (current_gdbarch, old_sp);
+      if (sp == old_sp)
+       {
+         if (INNER_THAN (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));
+    }
+  else
+    /* FIXME: cagney/2002-09-18: Hey, you loose!  Who knows how badly
+       aligned the SP is!  Further, per comment above, if the generic
+       dummy frame ends up empty (because nothing is pushed) GDB won't
+       be able to correctly perform back traces.  If a target is
+       having trouble with backtraces, first thing to do is add
+       FRAME_ALIGN() to its architecture vector.  After that, try
+       adding SAVE_DUMMY_FRAME_TOS() and modifying FRAME_CHAIN so that
+       when the next outer frame is a generic dummy, it returns the
+       current frame's base.  */
+    sp = old_sp;
 
   if (INNER_THAN (1, 2))
     {
@@ -1366,6 +1414,11 @@ hand_function_call (struct value *function, int nargs, struct value **args)
       sp += sizeof_dummy1;
     }
 
+  /* NOTE: cagney/2002-09-10: Don't bother re-adjusting the stack
+     after allocating space for the call dummy.  A target can specify
+     a SIZEOF_DUMMY1 (via SIZEOF_CALL_DUMMY_WORDS) such that all local
+     alignment requirements are met.  */
+
   funaddr = find_function_addr (function, &value_type);
   CHECK_TYPEDEF (value_type);
 
@@ -1562,7 +1615,8 @@ You must use a pointer to function type variable. Command ignored.", arg_name);
 
 
   /* Reserve space for the return structure to be written on the
-     stack, if necessary */
+     stack, if necessary.  Make certain that the value is correctly
+     aligned. */
 
   if (struct_return)
     {
@@ -1574,15 +1628,23 @@ You must use a pointer to function type variable. Command ignored.", arg_name);
        len = STACK_ALIGN (len);
       if (INNER_THAN (1, 2))
        {
-         /* stack grows downward */
+         /* Stack grows downward.  Align STRUCT_ADDR and SP after
+             making space for the return value.  */
          sp -= len;
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
          struct_addr = sp;
        }
       else
        {
-         /* stack grows upward */
+         /* Stack grows upward.  Align the frame, allocate space, and
+             then again, re-align the frame??? */
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
          struct_addr = sp;
          sp += len;
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
        }
     }
 
@@ -1778,14 +1840,13 @@ the function call).", name);
     do_cleanups (inf_status_cleanup);
 
     /* Figure out the value returned by the function.  */
-/* elz: I defined this new macro for the hppa architecture only.
-   this gives us a way to get the value returned by the function from the stack,
-   at the same address we told the function to put it.
-   We cannot assume on the pa that r28 still contains the address of the returned
-   structure. Usually this will be overwritten by the callee.
-   I don't know about other architectures, so I defined this macro
- */
-
+    /* elz: I defined this new macro for the hppa architecture only.
+       this gives us a way to get the value returned by the function
+       from the stack, at the same address we told the function to put
+       it.  We cannot assume on the pa that r28 still contains the
+       address of the returned structure. Usually this will be
+       overwritten by the callee.  I don't know about other
+       architectures, so I defined this macro */
 #ifdef VALUE_RETURNED_FROM_STACK
     if (struct_return)
       {
@@ -1793,12 +1854,26 @@ the function call).", name);
        return VALUE_RETURNED_FROM_STACK (value_type, struct_addr);
       }
 #endif
-
-    {
-      struct value *retval = value_being_returned (value_type, retbuf, struct_return);
-      do_cleanups (retbuf_cleanup);
-      return retval;
-    }
+    /* NOTE: cagney/2002-09-10: Only when the stack has been correctly
+       aligned (using frame_align()) do we can trust STRUCT_ADDR and
+       fetch the return value direct from the stack.  This lack of
+       trust comes about because legacy targets have a nasty habit of
+       silently, and local to PUSH_ARGUMENTS(), moving STRUCT_ADDR.
+       For such targets, just hope that value_being_returned() can
+       find the adjusted value.  */
+    if (struct_return && gdbarch_frame_align_p (current_gdbarch))
+      {
+        struct value *retval = value_at (value_type, struct_addr, NULL);
+        do_cleanups (retbuf_cleanup);
+        return retval;
+      }
+    else
+      {
+       struct value *retval = value_being_returned (value_type, retbuf,
+                                                    struct_return);
+       do_cleanups (retbuf_cleanup);
+       return retval;
+      }
   }
 }