This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] MIPS/Linux: Signal frame support for DSP registers
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: <gdb-patches at sourceware dot org>
- Cc: Eli Zaretskii <eliz at gnu dot org>
- Date: Mon, 21 May 2012 16:43:58 +0100
- Subject: [PATCH] MIPS/Linux: Signal frame support for DSP registers
Hello,
Here's a change for signal frame handling that I realised after recent
microMIPS considerations that is needed to complement MIPS/Linux DSP
register support that I added not so long ago.
There are no regressions in mips-linux-gnu test suite, but I believe
signal frame handling is not really well covered there, not at least as
far as MIPS DSP support is concerned. I have therefore used the following
trivial program to make sure unwinding works correctly through a signal
frame:
$ cat dspmult.c
#include <signal.h>
#include <stddef.h>
static void
segvaction (int signo, siginfo_t *info, void *context)
{
register unsigned long long acc0;
register unsigned long long acc1;
register unsigned long long acc2;
register unsigned long long acc3;
ucontext_t *uc = context;
asm volatile ("multu %q0, %1, %2" : "=a" (acc0) : "r" (0xc0000011), "r" (2));
asm volatile ("multu %q0, %1, %2" : "=a" (acc1) : "r" (0xc0000011), "r" (4));
asm volatile ("multu %q0, %1, %2" : "=a" (acc2) : "r" (0xc0000011), "r" (8));
asm volatile ("multu %q0, %1, %2" : "=a" (acc3) : "r" (0xc0000011), "r" (16));
asm volatile ("wrdsp %0" : : "r" (0xaa55aa55));
asm volatile ("" : : "a" (acc0), "a" (acc1), "a" (acc2), "a" (acc3));
asm volatile ("teq $0, $0");
}
int
main (void)
{
struct sigaction act =
{
.sa_sigaction = segvaction,
.sa_flags = SA_SIGINFO | SA_NODEFER,
};
register unsigned long long acc0;
register unsigned long long acc1;
register unsigned long long acc2;
register unsigned long long acc3;
sigemptyset (&act.sa_mask);
sigaction (SIGSEGV, &act, NULL);
asm volatile ("mtc1 $0, $f0");
asm volatile ("multu %q0, %1, %2" : "=a" (acc0) : "r" (0x80000001), "r" (2));
asm volatile ("multu %q0, %1, %2" : "=a" (acc1) : "r" (0x80000001), "r" (4));
asm volatile ("multu %q0, %1, %2" : "=a" (acc2) : "r" (0x80000001), "r" (8));
asm volatile ("multu %q0, %1, %2" : "=a" (acc3) : "r" (0x80000001), "r" (16));
asm volatile ("wrdsp %0" : : "r" (0x55aa55aa));
asm volatile ("" : : "a" (acc0), "a" (acc1), "a" (acc2), "a" (acc3));
asm volatile ("lw $0, 0($0)");
return 0;
}
While accessing main's DSP registers from the context of segvaction
correct original values are reported after my change has been applied,
while before -- it's the current values that are. I have verified the
values reported (as printed by "info registers") are consistent with the
values in uc as well.
While at it I realised this new feature really deserves a NEWS entry
which I originally didn't think of and given that we haven't made a
release with MIPS DSP support yet I would like to take this opportunity
and fix this mistake.
Eli, can you tell me if the NEWS entry is OK with you? Please note that
I deliberately say "Linux" rather than "GNU/Linux" here as all the DSP
support relies on a kernel feature; it does not rely on any C library or
other userland feature whatsoever. Thanks.
2012-05-21 Maciej W. Rozycki <macro@codesourcery.com>
gdb/
* NEWS: Add MIPS/Linux DSP support.
* mips-linux-tdep.c: Document post-2.6.12 o32 sigcontext layout.
(SIGCONTEXT_DSPCTL): New macro.
(SIGCONTEXT_HI1, SIGCONTEXT_LO1): Likewise.
(SIGCONTEXT_HI2, SIGCONTEXT_LO2): Likewise.
(SIGCONTEXT_HI3, SIGCONTEXT_LO3): Likewise.
(N64_SIGCONTEXT_HI1, N64_SIGCONTEXT_HI2): Likewise.
(N64_SIGCONTEXT_HI3): Likewise.
(N64_SIGCONTEXT_LO1, N64_SIGCONTEXT_LO2): Likewise.
(N64_SIGCONTEXT_LO3): Likewise.
(N64_SIGCONTEXT_DSPCTL): Likewise.
(N64_SIGCONTEXT_FPCSR): Clarify definition.
(mips_linux_o32_sigframe_init): Handle DSP registers.
(mips_linux_n32n64_sigframe_init): Likewise.
NB the way N64_SIGCONTEXT_FPCSR is defined and
mips_linux_n32n64_sigframe_init implemented makes me suspect we get the
value of the FP CSR wrong in the 64-bit case -- it's a 32-bit register and
code elsewhere assumes it's 64-bit, so presumably will access the whole
register slot rather than the right half of it. I'll have to check it.
Maciej
gdb-mips-dsp-sigtramp.diff
Index: gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-linux-tdep.c 2012-05-20 16:26:05.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c 2012-05-20 16:26:10.845566830 +0100
@@ -940,6 +940,8 @@ static const struct tramp_frame micromip
sigset_t sf_mask;
};
+ Pre-2.6.12 sigcontext:
+
struct sigcontext {
unsigned int sc_regmask; [Unused]
unsigned int sc_status;
@@ -961,6 +963,30 @@ static const struct tramp_frame micromip
unsigned long sc_sigset[4]; [kernel's sigset_t]
};
+ Post-2.6.12 sigcontext (SmartMIPS/DSP support added):
+
+ struct sigcontext {
+ unsigned int sc_regmask; [Unused]
+ unsigned int sc_status; [Unused]
+ unsigned long long sc_pc;
+ unsigned long long sc_regs[32];
+ unsigned long long sc_fpregs[32];
+ unsigned int sc_acx;
+ unsigned int sc_fpc_csr;
+ unsigned int sc_fpc_eir; [Unused]
+ unsigned int sc_used_math;
+ unsigned int sc_dsp;
+ [Alignment hole of four bytes]
+ unsigned long long sc_mdhi;
+ unsigned long long sc_mdlo;
+ unsigned long sc_hi1;
+ unsigned long sc_lo1;
+ unsigned long sc_hi2;
+ unsigned long sc_lo2;
+ unsigned long sc_hi3;
+ unsigned long sc_lo3;
+ };
+
The RT signal frames look like this:
struct rt_sigframe {
@@ -993,10 +1019,17 @@ static const struct tramp_frame micromip
#define SIGCONTEXT_REGS (2 * 8)
#define SIGCONTEXT_FPREGS (34 * 8)
#define SIGCONTEXT_FPCSR (66 * 8 + 4)
+#define SIGCONTEXT_DSPCTL (68 * 8 + 0)
#define SIGCONTEXT_HI (69 * 8)
#define SIGCONTEXT_LO (70 * 8)
#define SIGCONTEXT_CAUSE (71 * 8 + 0)
#define SIGCONTEXT_BADVADDR (71 * 8 + 4)
+#define SIGCONTEXT_HI1 (71 * 8 + 0)
+#define SIGCONTEXT_LO1 (71 * 8 + 4)
+#define SIGCONTEXT_HI2 (72 * 8 + 0)
+#define SIGCONTEXT_LO2 (72 * 8 + 4)
+#define SIGCONTEXT_HI3 (73 * 8 + 0)
+#define SIGCONTEXT_LO3 (73 * 8 + 4)
#define SIGCONTEXT_REG_SIZE 8
@@ -1072,18 +1105,49 @@ mips_linux_o32_sigframe_init (const stru
regs->fp_control_status
+ gdbarch_num_regs (gdbarch),
sigcontext_base + SIGCONTEXT_FPCSR);
+
+ if (regs->dspctl != -1)
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspctl + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_DSPCTL);
+
trad_frame_set_reg_addr (this_cache,
regs->hi + gdbarch_num_regs (gdbarch),
regs_base + SIGCONTEXT_HI);
trad_frame_set_reg_addr (this_cache,
regs->lo + gdbarch_num_regs (gdbarch),
regs_base + SIGCONTEXT_LO);
- trad_frame_set_reg_addr (this_cache,
- regs->cause + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_CAUSE);
- trad_frame_set_reg_addr (this_cache,
- regs->badvaddr + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_BADVADDR);
+
+ if (regs->dspacc != -1)
+ {
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 0 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_HI1);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 1 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_LO1);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 2 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_HI2);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 3 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_LO2);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 4 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_HI3);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 5 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_LO3);
+ }
+ else
+ {
+ trad_frame_set_reg_addr (this_cache,
+ regs->cause + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_CAUSE);
+ trad_frame_set_reg_addr (this_cache,
+ regs->badvaddr + gdbarch_num_regs (gdbarch),
+ sigcontext_base + SIGCONTEXT_BADVADDR);
+ }
/* Choice of the bottom of the sigframe is somewhat arbitrary. */
trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
@@ -1161,9 +1225,16 @@ mips_linux_o32_sigframe_init (const stru
#define N64_SIGCONTEXT_REGS (0 * 8)
#define N64_SIGCONTEXT_FPREGS (32 * 8)
#define N64_SIGCONTEXT_HI (64 * 8)
+#define N64_SIGCONTEXT_HI1 (65 * 8)
+#define N64_SIGCONTEXT_HI2 (66 * 8)
+#define N64_SIGCONTEXT_HI3 (67 * 8)
#define N64_SIGCONTEXT_LO (68 * 8)
+#define N64_SIGCONTEXT_LO1 (69 * 8)
+#define N64_SIGCONTEXT_LO2 (70 * 8)
+#define N64_SIGCONTEXT_LO3 (71 * 8)
#define N64_SIGCONTEXT_PC (72 * 8)
-#define N64_SIGCONTEXT_FPCSR (73 * 8)
+#define N64_SIGCONTEXT_FPCSR (73 * 8 + 0)
+#define N64_SIGCONTEXT_DSPCTL (74 * 8 + 0)
#define N64_SIGCONTEXT_REG_SIZE 8
@@ -1213,6 +1284,7 @@ mips_linux_n32n64_sigframe_init (const s
regs->fp_control_status
+ gdbarch_num_regs (gdbarch),
sigcontext_base + N64_SIGCONTEXT_FPCSR);
+
trad_frame_set_reg_addr (this_cache,
regs->hi + gdbarch_num_regs (gdbarch),
sigcontext_base + N64_SIGCONTEXT_HI);
@@ -1220,6 +1292,32 @@ mips_linux_n32n64_sigframe_init (const s
regs->lo + gdbarch_num_regs (gdbarch),
sigcontext_base + N64_SIGCONTEXT_LO);
+ if (regs->dspacc != -1)
+ {
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 0 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + N64_SIGCONTEXT_HI1);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 1 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + N64_SIGCONTEXT_LO1);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 2 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + N64_SIGCONTEXT_HI2);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 3 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + N64_SIGCONTEXT_LO2);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 4 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + N64_SIGCONTEXT_HI3);
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspacc + 5 + gdbarch_num_regs (gdbarch),
+ sigcontext_base + N64_SIGCONTEXT_LO3);
+ }
+ if (regs->dspctl != -1)
+ trad_frame_set_reg_addr (this_cache,
+ regs->dspctl + gdbarch_num_regs (gdbarch),
+ sigcontext_base + N64_SIGCONTEXT_DSPCTL);
+
/* Choice of the bottom of the sigframe is somewhat arbitrary. */
trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
}
Index: gdb-fsf-trunk-quilt/gdb/NEWS
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/NEWS 2012-05-20 16:26:04.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/NEWS 2012-05-20 16:29:02.275560354 +0100
@@ -3,6 +3,8 @@
*** Changes since GDB 7.4
+* GDB now supports access to MIPS DSP registers on Linux targets.
+
* GDB now supports debugging microMIPS binaries.
* The "info os" command on GNU/Linux can now display information on