This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[commit] Fix up signal frame unwinding for mips-linux
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sources dot redhat dot com
- Date: Sat, 2 Apr 2005 18:02:39 -0500
- Subject: [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,