This is the mail archive of the gdb-patches@sourceware.org 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]

[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


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