MIPS: ptrace: Change GP regset to use correct core dump register layout
[linux-drm-fsl-dcu.git] / arch / mips / kernel / ptrace.c
index 8f2130a2bbd33e2f48e34cd7a0ec43427df4a136..8bd13ed084d249a530b28702b093c721680978a9 100644 (file)
@@ -246,36 +246,160 @@ int ptrace_set_watch_regs(struct task_struct *child,
 
 /* regset get/set implementations */
 
-static int gpr_get(struct task_struct *target,
-                  const struct user_regset *regset,
-                  unsigned int pos, unsigned int count,
-                  void *kbuf, void __user *ubuf)
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
+
+static int gpr32_get(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    void *kbuf, void __user *ubuf)
 {
        struct pt_regs *regs = task_pt_regs(target);
+       u32 uregs[ELF_NGREG] = {};
+       unsigned i;
+
+       for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
+               /* k0/k1 are copied as zero. */
+               if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
+                       continue;
+
+               uregs[i] = regs->regs[i - MIPS32_EF_R0];
+       }
 
-       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                  regs, 0, sizeof(*regs));
+       uregs[MIPS32_EF_LO] = regs->lo;
+       uregs[MIPS32_EF_HI] = regs->hi;
+       uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
+       uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
+       uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
+       uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
+                                  sizeof(uregs));
 }
 
-static int gpr_set(struct task_struct *target,
-                  const struct user_regset *regset,
-                  unsigned int pos, unsigned int count,
-                  const void *kbuf, const void __user *ubuf)
+static int gpr32_set(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    const void *kbuf, const void __user *ubuf)
 {
-       struct pt_regs newregs;
-       int ret;
+       struct pt_regs *regs = task_pt_regs(target);
+       u32 uregs[ELF_NGREG];
+       unsigned start, num_regs, i;
+       int err;
+
+       start = pos / sizeof(u32);
+       num_regs = count / sizeof(u32);
+
+       if (start + num_regs > ELF_NGREG)
+               return -EIO;
+
+       err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
+                                sizeof(uregs));
+       if (err)
+               return err;
+
+       for (i = start; i < num_regs; i++) {
+               /*
+                * Cast all values to signed here so that if this is a 64-bit
+                * kernel, the supplied 32-bit values will be sign extended.
+                */
+               switch (i) {
+               case MIPS32_EF_R1 ... MIPS32_EF_R25:
+                       /* k0/k1 are ignored. */
+               case MIPS32_EF_R28 ... MIPS32_EF_R31:
+                       regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
+                       break;
+               case MIPS32_EF_LO:
+                       regs->lo = (s32)uregs[i];
+                       break;
+               case MIPS32_EF_HI:
+                       regs->hi = (s32)uregs[i];
+                       break;
+               case MIPS32_EF_CP0_EPC:
+                       regs->cp0_epc = (s32)uregs[i];
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
+
+#ifdef CONFIG_64BIT
+
+static int gpr64_get(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    void *kbuf, void __user *ubuf)
+{
+       struct pt_regs *regs = task_pt_regs(target);
+       u64 uregs[ELF_NGREG] = {};
+       unsigned i;
+
+       for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
+               /* k0/k1 are copied as zero. */
+               if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
+                       continue;
+
+               uregs[i] = regs->regs[i - MIPS64_EF_R0];
+       }
+
+       uregs[MIPS64_EF_LO] = regs->lo;
+       uregs[MIPS64_EF_HI] = regs->hi;
+       uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
+       uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
+       uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
+       uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
+                                  sizeof(uregs));
+}
 
-       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                &newregs,
-                                0, sizeof(newregs));
-       if (ret)
-               return ret;
+static int gpr64_set(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    const void *kbuf, const void __user *ubuf)
+{
+       struct pt_regs *regs = task_pt_regs(target);
+       u64 uregs[ELF_NGREG];
+       unsigned start, num_regs, i;
+       int err;
+
+       start = pos / sizeof(u64);
+       num_regs = count / sizeof(u64);
 
-       *task_pt_regs(target) = newregs;
+       if (start + num_regs > ELF_NGREG)
+               return -EIO;
+
+       err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
+                                sizeof(uregs));
+       if (err)
+               return err;
+
+       for (i = start; i < num_regs; i++) {
+               switch (i) {
+               case MIPS64_EF_R1 ... MIPS64_EF_R25:
+                       /* k0/k1 are ignored. */
+               case MIPS64_EF_R28 ... MIPS64_EF_R31:
+                       regs->regs[i - MIPS64_EF_R0] = uregs[i];
+                       break;
+               case MIPS64_EF_LO:
+                       regs->lo = uregs[i];
+                       break;
+               case MIPS64_EF_HI:
+                       regs->hi = uregs[i];
+                       break;
+               case MIPS64_EF_CP0_EPC:
+                       regs->cp0_epc = uregs[i];
+                       break;
+               }
+       }
 
        return 0;
 }
 
+#endif /* CONFIG_64BIT */
+
 static int fpr_get(struct task_struct *target,
                   const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
@@ -337,14 +461,16 @@ enum mips_regset {
        REGSET_FPR,
 };
 
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
+
 static const struct user_regset mips_regsets[] = {
        [REGSET_GPR] = {
                .core_note_type = NT_PRSTATUS,
                .n              = ELF_NGREG,
                .size           = sizeof(unsigned int),
                .align          = sizeof(unsigned int),
-               .get            = gpr_get,
-               .set            = gpr_set,
+               .get            = gpr32_get,
+               .set            = gpr32_set,
        },
        [REGSET_FPR] = {
                .core_note_type = NT_PRFPREG,
@@ -364,14 +490,18 @@ static const struct user_regset_view user_mips_view = {
        .n              = ARRAY_SIZE(mips_regsets),
 };
 
+#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
+
+#ifdef CONFIG_64BIT
+
 static const struct user_regset mips64_regsets[] = {
        [REGSET_GPR] = {
                .core_note_type = NT_PRSTATUS,
                .n              = ELF_NGREG,
                .size           = sizeof(unsigned long),
                .align          = sizeof(unsigned long),
-               .get            = gpr_get,
-               .set            = gpr_set,
+               .get            = gpr64_get,
+               .set            = gpr64_set,
        },
        [REGSET_FPR] = {
                .core_note_type = NT_PRFPREG,
@@ -384,25 +514,26 @@ static const struct user_regset mips64_regsets[] = {
 };
 
 static const struct user_regset_view user_mips64_view = {
-       .name           = "mips",
+       .name           = "mips64",
        .e_machine      = ELF_ARCH,
        .ei_osabi       = ELF_OSABI,
        .regsets        = mips64_regsets,
-       .n              = ARRAY_SIZE(mips_regsets),
+       .n              = ARRAY_SIZE(mips64_regsets),
 };
 
+#endif /* CONFIG_64BIT */
+
 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 {
 #ifdef CONFIG_32BIT
        return &user_mips_view;
-#endif
-
+#else
 #ifdef CONFIG_MIPS32_O32
-               if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
-                       return &user_mips_view;
+       if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
+               return &user_mips_view;
 #endif
-
        return &user_mips64_view;
+#endif
 }
 
 long arch_ptrace(struct task_struct *child, long request,