ptrace and emulated mfspr/mtspr on DSCR
Alexey Kardashevskiy
aik at ozlabs.ru
Fri Jul 6 17:30:12 EST 2012
Hi!
I am trying to change DSCR's value of a specific process with pid=XXX. For this, I attach by ptrace() to XXX, inject a piece of code which does mfspr/mtspr, "continue" XXX and see how it is changing. So far so good.
The problem is with "continue". The XXX process does not wake up until I press a key (if XXX is waiting on something like scanf() or gets()) OR it exits from sleep() if I change it to run sleep() in a loop.
Not sure if it matters but mfspr/mtspr are privileged instructions and are emulated by the kernel.
How to wake XXX up?
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <sys/user.h>
#include <stdio.h>
#include <stdlib.h>
void getdata(pid_t child, long addr, void *str)
{
unsigned long *ptr = (unsigned long *) str;
ptr[0] = ptrace(PTRACE_PEEKDATA, child, addr, NULL);
}
void putdata(pid_t child, long addr, void *str)
{
unsigned long *ptr = (unsigned long *) str;
ptrace(PTRACE_POKEDATA, child, addr, ptr[0]);
}
int main(int argc, char *argv[])
{
pid_t traced_process;
struct pt_regs regs, backup_regs;
unsigned long dscr = -1;
/*.set_dscr:
* 7f d1 03 a6 mtspr 17,r30
7d 82 10 08 twge r2,r2 <- set breakpoint */
unsigned int insert_set[] = { 0x7fd103a6, 0x7d821008 };
/*.get_dscr:
7f d1 02 a6 mfspr r30,17
7d 82 10 08 twge r2,r2 <- set breakpoint */
unsigned int insert_get[] = { 0x7fd102a6, 0x7d821008 };
char backup[8];
int len = 8;
if((argc < 2)||(sizeof(unsigned int)!=4)) {
printf("Usage: %s <pid to be traced> [dscr value]\n", argv[0], argv[1]);
exit(1);
}
if (argc > 2) {
dscr = atoi(argv[2]);
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process, NULL, NULL);
wait(NULL);
printf("Attached to pid=%u\n", traced_process);
ptrace(PTRACE_GETREGS, traced_process, NULL, ®s);
backup_regs = regs;
getdata(traced_process, regs.nip, backup);
if (dscr != -1) {
regs.gpr[30] = dscr;
putdata(traced_process, regs.nip, insert_set);
ptrace(PTRACE_SETREGS, traced_process, NULL, ®s);
printf("Setting DSCR = %x to gpr0\n", regs.gpr[30]);
} else {
putdata(traced_process, regs.nip, insert_get);
printf("Reading DSCR\n");
}
printf("Continued pid=%u\n", traced_process);
ptrace(PTRACE_CONT, traced_process, NULL, SIGCONT);
printf("waiting...\n");
wait(NULL); // <---------------- HERE IS THE PROBLEM
if (dscr == -1) {
printf("DSCR has been read\n");
ptrace(PTRACE_GETREGS, traced_process, NULL, ®s);
printf("Reading DSCR from gpr30 = %x\n", regs.gpr[30]);
}
printf("The process stopped, Putting back the original instructions\n");
putdata(traced_process, backup_regs.nip, backup);
ptrace(PTRACE_SETREGS, traced_process, NULL, &backup_regs);
printf("Letting it continue with original flow\n");
ptrace(PTRACE_DETACH, traced_process, NULL, NULL);
return 0;
}
--
Alexey
More information about the Linuxppc-dev
mailing list