s390: fix ptrace of user area if the inferior uses vector registers
[deliverable/linux.git] / arch / s390 / kernel / ptrace.c
index 99a567b70d16f6e18a0028b0221f2bb2962f2718..9eed6bb5c4a9931fbece1e06460b0e7a031df6fc 100644 (file)
@@ -248,14 +248,27 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr)
                 */
                tmp = 0;
 
+       } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) {
+               /*
+                * floating point control reg. is in the thread structure
+                */
+               tmp = child->thread.fp_regs.fpc;
+               tmp <<= BITS_PER_LONG - 32;
+
        } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
-               /* 
-                * floating point regs. are stored in the thread structure
+               /*
+                * floating point regs. are either in child->thread.fp_regs
+                * or the child->thread.vxrs array
                 */
-               offset = addr - (addr_t) &dummy->regs.fp_regs;
-               tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
-               if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
-                       tmp <<= BITS_PER_LONG - 32;
+               offset = addr - (addr_t) &dummy->regs.fp_regs.fprs;
+#ifdef CONFIG_64BIT
+               if (child->thread.vxrs)
+                       tmp = *(addr_t *)
+                              ((addr_t) child->thread.vxrs + 2*offset);
+               else
+#endif
+                       tmp = *(addr_t *)
+                              ((addr_t) &child->thread.fp_regs.fprs + offset);
 
        } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
                /*
@@ -383,16 +396,29 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
                 */
                return 0;
 
+       } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) {
+               /*
+                * floating point control reg. is in the thread structure
+                */
+               if ((unsigned int) data != 0 ||
+                   test_fp_ctl(data >> (BITS_PER_LONG - 32)))
+                       return -EINVAL;
+               child->thread.fp_regs.fpc = data >> (BITS_PER_LONG - 32);
+
        } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
                /*
-                * floating point regs. are stored in the thread structure
+                * floating point regs. are either in child->thread.fp_regs
+                * or the child->thread.vxrs array
                 */
-               if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
-                       if ((unsigned int) data != 0 ||
-                           test_fp_ctl(data >> (BITS_PER_LONG - 32)))
-                               return -EINVAL;
-               offset = addr - (addr_t) &dummy->regs.fp_regs;
-               *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
+               offset = addr - (addr_t) &dummy->regs.fp_regs.fprs;
+#ifdef CONFIG_64BIT
+               if (child->thread.vxrs)
+                       *(addr_t *)((addr_t)
+                               child->thread.vxrs + 2*offset) = data;
+               else
+#endif
+                       *(addr_t *)((addr_t)
+                               &child->thread.fp_regs.fprs + offset) = data;
 
        } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
                /*
@@ -611,12 +637,26 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
                 */
                tmp = 0;
 
+       } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) {
+               /*
+                * floating point control reg. is in the thread structure
+                */
+               tmp = child->thread.fp_regs.fpc;
+
        } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
                /*
-                * floating point regs. are stored in the thread structure 
+                * floating point regs. are either in child->thread.fp_regs
+                * or the child->thread.vxrs array
                 */
-               offset = addr - (addr_t) &dummy32->regs.fp_regs;
-               tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
+               offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs;
+#ifdef CONFIG_64BIT
+               if (child->thread.vxrs)
+                       tmp = *(__u32 *)
+                              ((addr_t) child->thread.vxrs + 2*offset);
+               else
+#endif
+                       tmp = *(__u32 *)
+                              ((addr_t) &child->thread.fp_regs.fprs + offset);
 
        } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
                /*
@@ -722,15 +762,28 @@ static int __poke_user_compat(struct task_struct *child,
                 */
                return 0;
 
-       } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+       } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) {
                /*
-                * floating point regs. are stored in the thread structure 
+                * floating point control reg. is in the thread structure
                 */
-               if (addr == (addr_t) &dummy32->regs.fp_regs.fpc &&
-                   test_fp_ctl(tmp))
+               if (test_fp_ctl(tmp))
                        return -EINVAL;
-               offset = addr - (addr_t) &dummy32->regs.fp_regs;
-               *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp;
+               child->thread.fp_regs.fpc = data;
+
+       } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+               /*
+                * floating point regs. are either in child->thread.fp_regs
+                * or the child->thread.vxrs array
+                */
+               offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs;
+#ifdef CONFIG_64BIT
+               if (child->thread.vxrs)
+                       *(__u32 *)((addr_t)
+                               child->thread.vxrs + 2*offset) = tmp;
+               else
+#endif
+                       *(__u32 *)((addr_t)
+                               &child->thread.fp_regs.fprs + offset) = tmp;
 
        } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
                /*
This page took 0.033125 seconds and 5 git commands to generate.