This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[commit] Fix up signal frame unwinding for mips-linux


We need to make an offset correction for big-endian signal frames
on MIPS GNU/Linux o32.  The saved register slots are 64-bit, but GDB wants
32-bit registers.  However, when I applied that adjustment, I botched
the registers that already had 32-bit slots - particularly FPCSR.  And
it turns out that using ptrace to put a bogus value in FPCSR can really ruin
your day (and crash your kernel).  So let's fix that :-)

This patch also corrects the floating-point registers.  There's no way to
get them right for both the r3000 and everything else; but "everything else"
is much larger, so I'm using the latter layout.

Tested on mips-linux, and committed.  The testsuite no longer crashes my
MIPS target, so I can make some more progress on the testsuite failures now.

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-04-02  Daniel Jacobowitz  <dan@codesourcery.com>

	* mips-linux-tdep.c (mips_linux_o32_sigframe_init): Adjust
	big-endian correction code to not offset 32-bit registers.
	Locate floating point registers correctly.

Index: mips-linux-tdep.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/mips-linux-tdep.c,v
retrieving revision 1.39
diff -u -p -r1.39 mips-linux-tdep.c
--- mips-linux-tdep.c	31 Mar 2005 19:58:25 -0000	1.39
+++ mips-linux-tdep.c	2 Apr 2005 22:52:11 -0000
@@ -1,6 +1,6 @@
 /* Target-dependent code for GNU/Linux on MIPS processors.
 
-   Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -976,6 +976,7 @@ mips_linux_o32_sigframe_init (const stru
   int ireg, reg_position;
   CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
   const struct mips_regnum *regs = mips_regnum (current_gdbarch);
+  CORE_ADDR regs_base;
 
   if (self == &mips_linux_o32_sigframe)
     sigcontext_base += SIGFRAME_SIGCONTEXT_OFFSET;
@@ -985,36 +986,52 @@ mips_linux_o32_sigframe_init (const stru
   /* I'm not proud of this hack.  Eventually we will have the
      infrastructure to indicate the size of saved registers on a
      per-frame basis, but right now we don't; the kernel saves eight
-     bytes but we only want four.  */
+     bytes but we only want four.  Use regs_base to access any
+     64-bit fields.  */
   if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
-    sigcontext_base += 4;
+    regs_base = sigcontext_base + 4;
+  else
+    regs_base = sigcontext_base;
 
 #if 0
   trad_frame_set_reg_addr (this_cache, ORIG_ZERO_REGNUM + NUM_REGS,
-			   sigcontext_base + SIGCONTEXT_REGS);
+			   regs_base + SIGCONTEXT_REGS);
 #endif
 
   for (ireg = 1; ireg < 32; ireg++)
     trad_frame_set_reg_addr (this_cache,
 			     ireg + MIPS_ZERO_REGNUM + NUM_REGS,
-			     sigcontext_base + SIGCONTEXT_REGS
+			     regs_base + SIGCONTEXT_REGS
 			     + ireg * SIGCONTEXT_REG_SIZE);
 
+  /* The way that floating point registers are saved, unfortunately,
+     depends on the architecture the kernel is built for.  For the r3000 and
+     tx39, four bytes of each register are at the beginning of each of the
+     32 eight byte slots.  For everything else, the registers are saved
+     using double precision; only the even-numbered slots are initialized,
+     and the high bits are the odd-numbered register.  Assume the latter
+     layout, since we can't tell, and it's much more common.  Which bits are
+     the "high" bits depends on endianness.  */
   for (ireg = 0; ireg < 32; ireg++)
-    trad_frame_set_reg_addr (this_cache, ireg + regs->fp0 + NUM_REGS,
-			     sigcontext_base + SIGCONTEXT_FPREGS
-			     + ireg * SIGCONTEXT_REG_SIZE);
+    if ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) != (ireg & 1))
+      trad_frame_set_reg_addr (this_cache, ireg + regs->fp0 + NUM_REGS,
+			       sigcontext_base + SIGCONTEXT_FPREGS + 4
+			       + (ireg & ~1) * SIGCONTEXT_REG_SIZE);
+    else
+      trad_frame_set_reg_addr (this_cache, ireg + regs->fp0 + NUM_REGS,
+			       sigcontext_base + SIGCONTEXT_FPREGS
+			       + (ireg & ~1) * SIGCONTEXT_REG_SIZE);
 
   trad_frame_set_reg_addr (this_cache, regs->pc + NUM_REGS,
-			   sigcontext_base + SIGCONTEXT_PC);
+			   regs_base + SIGCONTEXT_PC);
 
   trad_frame_set_reg_addr (this_cache,
 			   regs->fp_control_status + NUM_REGS,
 			   sigcontext_base + SIGCONTEXT_FPCSR);
   trad_frame_set_reg_addr (this_cache, regs->hi + NUM_REGS,
-			   sigcontext_base + SIGCONTEXT_HI);
+			   regs_base + SIGCONTEXT_HI);
   trad_frame_set_reg_addr (this_cache, regs->lo + NUM_REGS,
-			   sigcontext_base + SIGCONTEXT_LO);
+			   regs_base + SIGCONTEXT_LO);
   trad_frame_set_reg_addr (this_cache, regs->cause + NUM_REGS,
 			   sigcontext_base + SIGCONTEXT_CAUSE);
   trad_frame_set_reg_addr (this_cache, regs->badvaddr + NUM_REGS,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]