aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace.c
diff options
context:
space:
mode:
authorMike Wolf <mjw@linux.vnet.ibm.com>2011-03-20 20:14:53 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-03-20 20:18:14 -0400
commita71f5d5d279375205009a4be56a3cf6682921292 (patch)
treefde8b1e5958317268c9ce3b616cd4ee8d390502d /arch/powerpc/kernel/ptrace.c
parentd6a2639b887fcf90b422caccca4aee216bd1120e (diff)
powerpc/ptrace: Remove BUG_ON when full register set not available
In some cases during a threaded core dump not all the threads will have a full register set. This happens when the signal causing the core dump races with a thread exiting. The race happens when the exiting thread has entered the kernel for the last time before the signal arrives, but doesn't get far enough through the exit code to avoid being included in the core dump. So we get a thread included in the core dump which is never going to go out to userspace again and only has a partial register set recorded Normally we would catch each thread as it is about to go into userspace and capture the full register set then. However, this exiting thread is never going to go out to userspace again, so we have no way to capture its full register set. It doesn't really matter, though, as this is a thread which is effectively already dead. So instead of hitting a BUG() in this case (a really bad choice of action in the first place), we use a poison value for the register values. [BenH]: Some cosmetic/stylistic changes and fix build on ppc32 Signed-off-by: Mike Wolf <mjw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r--arch/powerpc/kernel/ptrace.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 906536998291..895b082f1e48 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -229,12 +229,16 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset,
229 unsigned int pos, unsigned int count, 229 unsigned int pos, unsigned int count,
230 void *kbuf, void __user *ubuf) 230 void *kbuf, void __user *ubuf)
231{ 231{
232 int ret; 232 int i, ret;
233 233
234 if (target->thread.regs == NULL) 234 if (target->thread.regs == NULL)
235 return -EIO; 235 return -EIO;
236 236
237 CHECK_FULL_REGS(target->thread.regs); 237 if (!FULL_REGS(target->thread.regs)) {
238 /* We have a partial register set. Fill 14-31 with bogus values */
239 for (i = 14; i < 32; i++)
240 target->thread.regs->gpr[i] = NV_REG_POISON;
241 }
238 242
239 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 243 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
240 target->thread.regs, 244 target->thread.regs,
@@ -641,11 +645,16 @@ static int gpr32_get(struct task_struct *target,
641 compat_ulong_t *k = kbuf; 645 compat_ulong_t *k = kbuf;
642 compat_ulong_t __user *u = ubuf; 646 compat_ulong_t __user *u = ubuf;
643 compat_ulong_t reg; 647 compat_ulong_t reg;
648 int i;
644 649
645 if (target->thread.regs == NULL) 650 if (target->thread.regs == NULL)
646 return -EIO; 651 return -EIO;
647 652
648 CHECK_FULL_REGS(target->thread.regs); 653 if (!FULL_REGS(target->thread.regs)) {
654 /* We have a partial register set. Fill 14-31 with bogus values */
655 for (i = 14; i < 32; i++)
656 target->thread.regs->gpr[i] = NV_REG_POISON;
657 }
649 658
650 pos /= sizeof(reg); 659 pos /= sizeof(reg);
651 count /= sizeof(reg); 660 count /= sizeof(reg);