|
From: Julian S. <js...@ac...> - 2007-11-19 02:43:39
|
Paul Valgrind has an mechanism whereby it can attach GDB to the client process, so users can poke around when an error occurs to see what's going on. It works using fork/ptrace. See coregrind/m_debugger.c. Recently said mechanism stopped working on amd64-linux. Turned out to be that the kernel's sanity checking for ptrace(PTRACE_SETREGS, ...) was tightened up around 2.6.20/21, causing the failure. Easily fixed. See http://bugs.kde.org/show_bug.cgi?id=145622 Now I've been trying to get same functionality implemented for ppc64-linux (it never has been so far). See http://bugs.kde.org/show_bug.cgi?id=151908 After some futzing around it appears that the mechanism works for ppc32-linux and ppc64-linux for kernel 2.6.20 but fails in some bizarre way on 2.6.23. So now I'm wondering if ptrace handling on ppc platforms has also been made more paranoid, or otherwise changed, lately? Do you know? Thanks, J |
|
From: Paul M. <pa...@sa...> - 2007-11-19 03:28:47
|
Julian Seward writes: > After some futzing around it appears that > the mechanism works for ppc32-linux and ppc64-linux for kernel 2.6.20 > but fails in some bizarre way on 2.6.23. > > So now I'm wondering if ptrace handling on ppc platforms has also > been made more paranoid, or otherwise changed, lately? Do you know? There were a bunch of ptrace changes for ppc/ppc64 that went in to 2.6.23, in part to allow gdb to restart system calls properly after executing a function in the child. There was also some consolidation of the code for PEEKDATA and POKEDATA into generic code. The only thing that I know of where we made things more paranoid is that ptrace used to be able to change FE0/1 in the MSR on 64-bit platforms (but not 32-bit), which is is now not allowed (if you set them this way, the change wouldn't stick anyway). It's certainly possible that we broke something along the way. Do you have anything more specific about which ptrace call is failing or misbehaving, and in what way? Paul. |
|
From: Julian S. <js...@ac...> - 2007-11-19 11:53:19
|
> It's certainly possible that we broke something along the way. Do you
> have anything more specific about which ptrace call is failing or
> misbehaving, and in what way?
Some times the ptrace'd process seems to get whacked with SIGSEGV
around the time it is being ptrace-POKE_USR'd.
But there's something else I don't understand. On x86 and amd64,
the child's registers are set by filling in a "struct vki_user_regs_struct
regs" and doing ptrace(SETREGS) on it. On ppc32/64, there are a whole
sequence of PTRACE_POKEUSRs, one for each register. I don't know
why it is done differently. Is it you that wrote this code originally
(in your 2.2.0/2.4.0-ppc variants)?
I changed the code to use SETREGS, as shown below, and now that ptrace fails
thusly:
ptrace(PTRACE_SETREGS, 32331, 0, 0x46c1a2c) = -1 EFAULT (Bad address)
I checked for an obvious snafu, that "struct vki_user_regs_struct"
(defined in Valgrind's include/vki/vki-ppc32-linux.h) is identical to
"struct pt_regs" (in linux-2.6.23/include/asm-powerpc/ptrace.h) and
it does seem identical.
So, I dunno. The code below seems reasonable. Why would the kernel
EFAULT it? Do some of the not-filled-in fields (which are memset-0'd)
need to be filled in? I think these are: msr mq trap dar dsisr result.
J
#elif defined(VGP_ppc32_linux)
Int rc;
struct vki_user_regs_struct regs;
VG_(memset)(®s, 0, sizeof(regs));
regs.gpr[0 ] = vex->guest_GPR0;
regs.gpr[1 ] = vex->guest_GPR1;
regs.gpr[2 ] = vex->guest_GPR2;
regs.gpr[3 ] = vex->guest_GPR3;
regs.orig_gpr3 = vex->guest_GPR3;
regs.gpr[4 ] = vex->guest_GPR4;
regs.gpr[5 ] = vex->guest_GPR5;
regs.gpr[6 ] = vex->guest_GPR6;
regs.gpr[7 ] = vex->guest_GPR7;
regs.gpr[8 ] = vex->guest_GPR8;
regs.gpr[9 ] = vex->guest_GPR9;
regs.gpr[10] = vex->guest_GPR10;
regs.gpr[11] = vex->guest_GPR11;
regs.gpr[12] = vex->guest_GPR12;
regs.gpr[13] = vex->guest_GPR13;
regs.gpr[14] = vex->guest_GPR14;
regs.gpr[15] = vex->guest_GPR15;
regs.gpr[16] = vex->guest_GPR16;
regs.gpr[17] = vex->guest_GPR17;
regs.gpr[18] = vex->guest_GPR18;
regs.gpr[19] = vex->guest_GPR19;
regs.gpr[20] = vex->guest_GPR20;
regs.gpr[21] = vex->guest_GPR21;
regs.gpr[22] = vex->guest_GPR22;
regs.gpr[23] = vex->guest_GPR23;
regs.gpr[24] = vex->guest_GPR24;
regs.gpr[25] = vex->guest_GPR25;
regs.gpr[26] = vex->guest_GPR26;
regs.gpr[27] = vex->guest_GPR27;
regs.gpr[28] = vex->guest_GPR28;
regs.gpr[29] = vex->guest_GPR29;
regs.gpr[30] = vex->guest_GPR30;
regs.gpr[31] = vex->guest_GPR31;
regs.nip = vex->guest_CIA;
regs.ccr = LibVEX_GuestPPC32_get_CR(vex);
regs.link = vex->guest_LR;
regs.ctr = vex->guest_CTR;
regs.xer = LibVEX_GuestPPC32_get_XER(vex);
rc = VG_(ptrace)(13 /*VKI_PTRACE_SETREGS*/, pid, NULL, ®s);
VG_(printf)("SETREGS got %d\n", rc);
return rc;
|