In some cases during a threaded core dump not all 
the threads will have a full register set.  This
will cause problems when the sigkill is sent to
the thread.  To solve this problem a poison value
(0xdeadbeef) will be placed in the buffer in place 
of the actual register values.  This will affect
gpr14 to gpr31.

Signed-off-by: Mike Wolf <[email protected]>

----------

--- ptracev2.orig/include/linux/regset.h        2011-02-20 12:15:57.000000000 
-0600
+++ ptracev2/include/linux/regset.h     2011-02-28 13:33:36.685302349 -0600
@@ -240,6 +240,34 @@ static inline int user_regset_copyout(un
        }
        return 0;
 }
+/* want the count to be the registers 14-31 inclusive */
+#define POISON_REG_CNT (PT_R31-PT_R14+1)
+static inline int user_regset_copyout_poison(unsigned int *pos,
+                                          unsigned int *count,
+                                          void **kbuf, void __user **ubuf,
+                                          const int start_pos,
+                                          const int end_pos)
+{
+       long poison_data[POISON_REG_CNT] = { [0 ... POISON_REG_CNT-1] = 
0xdeadbeefdeadbeefUL };
+
+       if (*count == 0)
+               return 0;
+       BUG_ON(*pos < start_pos);
+       if (end_pos < 0 || *pos < end_pos) {
+               unsigned int copy = (end_pos < 0 ? *count
+                                    : min(*count, end_pos - *pos));
+               if (*kbuf) {
+                       memset(*kbuf, 0xdeadbeef, copy);
+                       *kbuf += copy;
+               } else if (__copy_to_user(*ubuf,poison_data, copy))
+                       return -EFAULT;
+               else
+                       *ubuf += copy;
+               *pos += copy;
+               *count -= copy;
+       }
+       return 0;
+}
 
 static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
                                     const void **kbuf,
--- ptracev2.orig/arch/powerpc/kernel/ptrace.c  2011-02-20 12:15:57.000000000 
-0600
+++ ptracev2/arch/powerpc/kernel/ptrace.c       2011-03-01 13:49:12.686354353 
-0600
@@ -234,11 +234,29 @@ static int gpr_get(struct task_struct *t
        if (target->thread.regs == NULL)
                return -EIO;
 
-       CHECK_FULL_REGS(target->thread.regs);
 
-       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                 target->thread.regs,
-                                 0, offsetof(struct pt_regs, msr));
+       if (!FULL_REGS(target->thread.regs)) {
+                /* Don't have the full register set. Copy out register r0-r13 
*/
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         target->thread.regs,
+                                         0, sizeof(long)*PT_R14);
+
+               /* Dont want to change the actual register values so rather 
than read the */
+               /* actual register copy a poison value into the buffer instead  
          */
+               if (!ret)
+                       ret = user_regset_copyout_poison(&pos, &count, &kbuf, 
&ubuf,
+                                                 sizeof(long)*PT_R14, 
offsetof(struct pt_regs, nip));
+
+               /* Copy out the rest of the registers as usual */
+               if (!ret)
+                       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                                 target->thread.regs,
+                                                 offsetof(struct pt_regs, 
nip), offsetof(struct pt_regs, msr));
+               
+       } else 
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         target->thread.regs,
+                                         0, offsetof(struct pt_regs, msr));
        if (!ret) {
                unsigned long msr = get_user_msr(target);
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
@@ -645,11 +663,29 @@ static int gpr32_get(struct task_struct 
        if (target->thread.regs == NULL)
                return -EIO;
 
-       CHECK_FULL_REGS(target->thread.regs);
-
        pos /= sizeof(reg);
        count /= sizeof(reg);
 
+       if(!FULL_REGS(target->thread.regs)) {
+               if (kbuf) {
+                       /* Don't have the full register set. Copy out register 
r0-r13 */
+                       for (; count > 0 && pos < PT_R14; --count)
+                               *k++ = regs[pos++];
+
+                       /* Dont want to change the actual register values so 
rather than read the */
+                       /* actual register copy a poison value into the buffer 
instead            */
+                       for (; count > 0 && pos <= PT_R31; --count,pos++)
+                               *k++ = 0xdeadbeef;
+
+               } else { 
+                       for (; count > 0 && pos < PT_R14; --count)
+                               if (__put_user((compat_ulong_t) regs[pos++], 
u++))
+                                       return -EFAULT;
+                       for (; count > 0 && pos <= PT_R31; --count,pos++)
+                               if (__put_user((compat_ulong_t) 0xdeadbeef, 
u++))
+                                       return -EFAULT;
+               }
+       }
        if (kbuf)
                for (; count > 0 && pos < PT_MSR; --count)
                        *k++ = regs[pos++];


_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to