hi,
I encountered one problem when running ptrace test case which
is in the attachment, the situation is this: traced process's
syscall parameter needs to be accessed, but for sys_clone system
call with clone_flag (CLONE_VFORK | CLONE_VM | SIGCHLD) parameter.
This syscall's parameter accessing result is wrong.
The reason is that vforked child process mm point is the same,
but tgid is different. Without this patch find_thread_for_addr
will return vforked process if vforked process is also stopped,
but not the thread which calls vfork syscall.
thanks
bibo,mao
------------------------------------------------------------------
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index aa705e4..2131db4 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -607,7 +607,7 @@ find_thread_for_addr (struct task_struct
*/
list_for_each_safe(this, next, ¤t->children) {
p = list_entry(this, struct task_struct, sibling);
- if (p->mm != mm)
+ if (p->tgid != child->tgid)
continue;
if (thread_matches(p, addr)) {
child = p;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sched.h>
#include <asm/rse.h>
//#include <asm/ptrace.h>
#include <asm/ptrace_offsets.h>
#define PTRACE_EVENT_FORK 1
#define PTRACE_EVENT_VFORK 2
#define PTRACE_EVENT_CLONE 3
#define PTRACE_EVENT_EXEC 4
#define PTRACE_EVENT_VFORK_DONE 5
#define PTRACE_EVENT_EXIT 6
#define PTRACE_SETOPTIONS 0x4200
#define PTRACE_GETEVENTMSG 0x4201
#define PTRACE_O_TRACESYSGOOD 0x00000001
#define PTRACE_O_TRACEFORK 0x00000002
#define PTRACE_O_TRACEVFORK 0x00000004
#define PTRACE_O_TRACECLONE 0x00000008
#define PTRACE_O_TRACEEXEC 0x00000010
#define PTRACE_O_TRACEVFORKDONE 0x00000020
#define PTRACE_O_TRACEEXIT 0x00000040
#define PALL PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE \
| PTRACE_O_TRACEEXEC | PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACEEXIT
void fetch_clone_flags(pid_t pid, unsigned long* clone_flags)
{
struct pt_all_user_regs ptregs;
unsigned long bsp, cfm, sof, sol;
unsigned long addr;
long ret;
ret = ptrace(PTRACE_GETREGS, pid, 0, (unsigned long)&ptregs);
bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
sof = (cfm >> 0) & 0x7f;
sol = (cfm >> 7) & 0x7f;
bsp = (unsigned long) ia64_rse_skip_regs((void *) bsp, -sof + sol);
addr= (unsigned long) ia64_rse_skip_regs((void *) bsp, 0);
ret = ptrace (PTRACE_PEEKTEXT, pid, addr, (unsigned long) clone_flags);
*clone_flags = ret;
}
/* Wrapper function for waitpid which handles EINTR. */
static int my_waitpid (int pid, int *status, int flags)
{
int ret;
int old_status = status ? *status : 0;
do {
ret = waitpid (pid, status, flags);
}
while (ret == -1 && errno == EINTR);
if (ret == 0 && status != 0)
*status = old_status;
return ret;
}
int main() {
unsigned long pid, npid ;
int status, event,ret, child_status;
char *stack ;
unsigned long clone_flags;
pid = fork();
if(pid == 0)
{
ptrace(PTRACE_TRACEME,0,NULL,NULL) ;
kill (getpid (), SIGSTOP);
if (vfork() == 0){
execve("/bin/true",NULL,NULL) ;
}
exit(0) ;
}
ret = my_waitpid(pid, &status, 0);
if (!WIFSTOPPED(status)) {
perror("waitpid failed unexpected tstatus \n");
return -1;
}
if (ptrace(PTRACE_SETOPTIONS,pid,NULL,PALL) < 0) {
perror("PTRACE_SETOPTIONS not supported\n");
return -1;
}
if (ptrace(PTRACE_CONT,pid,0,0) < 0) {
perror("PTRACE_CONT \n");
return -1;
}
if ( my_waitpid(pid,&status,0) < 0) {
perror("wait4 failed");
return -1;
}
event = (status >> 16) & 0xffff ;
if (event == PTRACE_EVENT_FORK
|| event == PTRACE_EVENT_VFORK
|| event == PTRACE_EVENT_CLONE) {
if (ptrace(PTRACE_GETEVENTMSG,pid,NULL,&npid) < 0) {
perror("PTRACE_GETEVENTMSG\n");
return -1;
}
sleep(1);
fetch_clone_flags(pid, &clone_flags);
if (clone_flags == (CLONE_VFORK | CLONE_VM | SIGCHLD))
printf("PTRACE_PEEKUSER succeed\n");
else
printf("PTRACE_PEEKUSER failed\n");
if (my_waitpid(npid,&child_status,0) < 0) {
perror("waitpid \n");
return -1;
}
ptrace (PTRACE_KILL, npid, 0, 0);
ptrace (PTRACE_KILL, pid, 0, 0);
//ptrace(PTRACE_CONT, npid, 0, WSTOPSIG(child_status));
//ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
my_waitpid(-1,&status,0);
}
return 0 ;
}