support PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK, PTRACE_O_TRACEVFORKDONE.
to start with a SIGSTOP, do not set proc->ftn->status to PS_RUNNING in __runq_add_proc(). change vfork() set CLONE_VFORK. refs #266 refs #267 refs #372 support PTRACE_GETEVENTMSG. to store ptrace event, add 'unsigned long ptrace_eventmsg;' member in struct fork_tree_node. refs #273
This commit is contained in:
@ -528,6 +528,7 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c,
|
||||
proc = (struct process *)packet->arg;
|
||||
|
||||
settid(proc, 0, ihk_mc_get_processor_id(), -1);
|
||||
proc->ftn->status = PS_RUNNING;
|
||||
runq_add_proc(proc, ihk_mc_get_processor_id());
|
||||
|
||||
//cpu_local_var(next) = (struct process *)packet->arg;
|
||||
|
||||
@ -296,6 +296,12 @@ struct fork_tree_node {
|
||||
*/
|
||||
int ptrace;
|
||||
|
||||
/* Store ptrace event message.
|
||||
PTRACE_O_xxx will store event message here.
|
||||
PTRACE_GETEVENTMSG will get from here.
|
||||
*/
|
||||
unsigned long ptrace_eventmsg;
|
||||
|
||||
/* Store event related to signal. For example,
|
||||
it represents that the proceess has been resumed by SIGCONT. */
|
||||
int signal_flags;
|
||||
|
||||
@ -349,7 +349,7 @@ int ptrace_traceme(void){
|
||||
struct fork_tree_node *child, *next;
|
||||
dkprintf("ptrace_traceme,pid=%d,proc->ftn->parent=%p\n", proc->ftn->pid, proc->ftn->parent);
|
||||
|
||||
if (proc->ftn->parent == NULL) {
|
||||
if (proc->ftn->parent == NULL || proc->ftn->ptrace) {
|
||||
error = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
@ -2183,7 +2183,7 @@ void __runq_add_proc(struct process *proc, int cpu_id)
|
||||
list_add_tail(&proc->sched_list, &v->runq);
|
||||
++v->runq_len;
|
||||
proc->cpu_id = cpu_id;
|
||||
proc->ftn->status = PS_RUNNING;
|
||||
//proc->ftn->status = PS_RUNNING; /* not set here */
|
||||
get_cpu_local_var(cpu_id)->status = CPU_STATUS_RUNNING;
|
||||
|
||||
dkprintf("runq_add_proc(): tid %d added to CPU[%d]'s runq\n",
|
||||
|
||||
168
kernel/syscall.c
168
kernel/syscall.c
@ -1442,7 +1442,7 @@ static int ptrace_report_exec(struct process *proc)
|
||||
long rc;
|
||||
struct siginfo info;
|
||||
|
||||
if (!(proc->ftn->ptrace & PT_TRACE_EXEC)) {
|
||||
if (!(proc->ftn->ptrace & (PT_TRACE_EXEC|PTRACE_O_TRACEEXEC))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1485,6 +1485,109 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int ptrace_check_clone_event(struct process *proc, int clone_flags)
|
||||
{
|
||||
int event = 0;
|
||||
|
||||
if (clone_flags & CLONE_VFORK) {
|
||||
/* vfork */
|
||||
if (proc->ftn->ptrace & PTRACE_O_TRACEVFORK) {
|
||||
event = PTRACE_EVENT_VFORK;
|
||||
}
|
||||
if (proc->ftn->ptrace & PTRACE_O_TRACEVFORKDONE) {
|
||||
event = PTRACE_EVENT_VFORK_DONE;
|
||||
}
|
||||
} else if ((clone_flags & CSIGNAL) == SIGCHLD) {
|
||||
/* fork */
|
||||
if (proc->ftn->ptrace & PTRACE_O_TRACEFORK) {
|
||||
event = PTRACE_EVENT_FORK;
|
||||
}
|
||||
} else {
|
||||
/* clone */
|
||||
if (proc->ftn->ptrace & PTRACE_O_TRACECLONE) {
|
||||
event = PTRACE_EVENT_CLONE;
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
static int ptrace_report_clone(struct process *proc, struct process *new, int event)
|
||||
{
|
||||
dkprintf("ptrace_report_clone,enter\n");
|
||||
int error = 0;
|
||||
long rc;
|
||||
struct siginfo info;
|
||||
|
||||
/* Save reason why stopped and process state for wait4() to reap */
|
||||
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
|
||||
proc->ftn->exit_status = (SIGTRAP | (event << 8));
|
||||
/* Transition process state */
|
||||
proc->ftn->status = PS_TRACED;
|
||||
proc->ftn->ptrace_eventmsg = new->ftn->pid;
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
|
||||
dkprintf("ptrace_report_clone,kill SIGCHLD\n");
|
||||
if (proc->ftn->parent) {
|
||||
/* kill SIGCHLD */
|
||||
ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock);
|
||||
if (proc->ftn->parent->owner) {
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = SIGCHLD;
|
||||
info.si_code = CLD_TRAPPED;
|
||||
info._sifields._sigchld.si_pid = proc->ftn->pid;
|
||||
info._sifields._sigchld.si_status = proc->ftn->exit_status;
|
||||
rc = do_kill(proc->ftn->parent->pid, -1, SIGCHLD, &info, 0);
|
||||
if(rc < 0) {
|
||||
dkprintf("ptrace_report_clone,do_kill failed\n");
|
||||
}
|
||||
}
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock);
|
||||
|
||||
/* Wake parent (if sleeping in wait4()) */
|
||||
waitq_wakeup(&proc->ftn->parent->waitpid_q);
|
||||
}
|
||||
|
||||
if (event != PTRACE_EVENT_VFORK_DONE) {
|
||||
/* PTRACE_EVENT_FORK or PTRACE_EVENT_VFORK or PTRACE_EVENT_CLONE */
|
||||
|
||||
struct fork_tree_node *child, *next;
|
||||
|
||||
/* set ptrace features to new process */
|
||||
ihk_mc_spinlock_lock_noirq(&new->ftn->lock);
|
||||
|
||||
new->ftn->ptrace = proc->ftn->ptrace;
|
||||
new->ftn->ppid_parent = new->ftn->parent; /* maybe proc */
|
||||
|
||||
ihk_mc_spinlock_lock_noirq(&new->ftn->parent->lock);
|
||||
list_for_each_entry_safe(child, next, &new->ftn->parent->children, siblings_list) {
|
||||
if(child == new->ftn) {
|
||||
list_del(&child->siblings_list);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
panic("ptrace_report_clone: missing parent-child relationship.");
|
||||
found:
|
||||
ihk_mc_spinlock_unlock_noirq(&new->ftn->parent->lock);
|
||||
|
||||
new->ftn->parent = proc->ftn->parent; /* new ptracing parent */
|
||||
|
||||
ihk_mc_spinlock_lock_noirq(&new->ftn->parent->lock);
|
||||
list_add_tail(&new->ftn->ptrace_siblings_list, &new->ftn->parent->ptrace_children);
|
||||
ihk_mc_spinlock_unlock_noirq(&new->ftn->parent->lock);
|
||||
|
||||
/* trace and SIGSTOP */
|
||||
new->ftn->exit_status = SIGSTOP;
|
||||
new->ftn->status = PS_TRACED;
|
||||
|
||||
ihk_mc_spinlock_unlock_noirq(&new->ftn->lock);
|
||||
}
|
||||
|
||||
peekuser(proc, NULL);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(execve)
|
||||
{
|
||||
int error;
|
||||
@ -1628,6 +1731,7 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||
struct process *new;
|
||||
ihk_mc_user_context_t ctx1;
|
||||
struct syscall_request request1 IHK_DMA_ALIGN;
|
||||
int ptrace_event = 0;
|
||||
|
||||
dkprintf("do_fork,flags=%08x,newsp=%lx,ptidptr=%lx,ctidptr=%lx,tls=%lx,curpc=%lx,cursp=%lx",
|
||||
clone_flags, newsp, parent_tidptr, child_tidptr, tlsblock_base, curpc, cursp);
|
||||
@ -1737,32 +1841,30 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||
|
||||
ihk_mc_syscall_ret(new->uctx) = 0;
|
||||
|
||||
if (cpu_local_var(current)->ftn->ptrace) {
|
||||
ptrace_event = ptrace_check_clone_event(cpu_local_var(current), clone_flags);
|
||||
if (ptrace_event) {
|
||||
ptrace_report_clone(cpu_local_var(current), new, ptrace_event);
|
||||
}
|
||||
}
|
||||
|
||||
dkprintf("clone: kicking scheduler!,cpuid=%d pid=%d tid=%d\n", cpuid, new->ftn->pid, new->ftn->tid);
|
||||
runq_add_proc(new, cpuid);
|
||||
|
||||
if (ptrace_event) {
|
||||
schedule();
|
||||
}
|
||||
|
||||
return new->ftn->tid;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(vfork)
|
||||
{
|
||||
return do_fork(SIGCHLD, 0, 0, 0, 0, ihk_mc_syscall_pc(ctx), ihk_mc_syscall_sp(ctx));
|
||||
return do_fork(CLONE_VFORK|SIGCHLD, 0, 0, 0, 0, ihk_mc_syscall_pc(ctx), ihk_mc_syscall_sp(ctx));
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(clone)
|
||||
{
|
||||
/* If CLONE_VM flag is not present, we assume this clone(2)
|
||||
* request is induced by the fork(2) wrapper of glibc.
|
||||
*/
|
||||
if ((ihk_mc_syscall_arg0(ctx) & CLONE_VM) == 0) {
|
||||
if (cpu_local_var(current)->ftn == NULL) {
|
||||
panic("No ftn for current process present.\n");
|
||||
}
|
||||
if ((cpu_local_var(current)->ftn->ptrace &
|
||||
PTRACE_O_TRACEFORK) != 0) {
|
||||
panic("We do not have PTRACE_O_TRACEFORK implementation yet.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return do_fork((int)ihk_mc_syscall_arg0(ctx), ihk_mc_syscall_arg1(ctx),
|
||||
ihk_mc_syscall_arg2(ctx), ihk_mc_syscall_arg3(ctx),
|
||||
ihk_mc_syscall_arg4(ctx), ihk_mc_syscall_pc(ctx),
|
||||
@ -2530,8 +2632,13 @@ static int ptrace_setoptions(int pid, int flags)
|
||||
* Following options are pretended to be supported for the time being:
|
||||
* PTRACE_O_TRACESYSGOOD
|
||||
* PTRACE_O_TRACEFORK
|
||||
* PTRACE_O_TRACEVFORK
|
||||
* PTRACE_O_TRACEVFORKDONE
|
||||
*/
|
||||
if (flags & ~(PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEFORK)) {
|
||||
if (flags & ~(PTRACE_O_TRACESYSGOOD|
|
||||
PTRACE_O_TRACEFORK|
|
||||
PTRACE_O_TRACEVFORK|
|
||||
PTRACE_O_TRACEVFORKDONE)) {
|
||||
kprintf("ptrace_setoptions: not supported flag %x\n", flags);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@ -2543,6 +2650,7 @@ static int ptrace_setoptions(int pid, int flags)
|
||||
goto unlockout;
|
||||
}
|
||||
|
||||
child->ftn->ptrace &= ~PTRACE_O_MASK; /* PT_TRACE_EXEC remains */
|
||||
child->ftn->ptrace |= flags;
|
||||
ret = 0;
|
||||
|
||||
@ -2634,6 +2742,30 @@ out_notfound:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static long ptrace_geteventmsg(int pid, long data)
|
||||
{
|
||||
unsigned long *msg_p = (unsigned long *)data;
|
||||
long rc = -ESRCH;
|
||||
struct process *child;
|
||||
ihk_spinlock_t *savelock;
|
||||
unsigned long irqstate;
|
||||
|
||||
child = findthread_and_lock(pid, -1, &savelock, &irqstate);
|
||||
if (!child) {
|
||||
return -ESRCH;
|
||||
}
|
||||
if (child->ftn->status == PS_TRACED) {
|
||||
if (copy_to_user(child, msg_p, &child->ftn->ptrace_eventmsg, sizeof(*msg_p))) {
|
||||
rc = -EFAULT;
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
ihk_mc_spinlock_unlock(savelock, irqstate);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(ptrace)
|
||||
{
|
||||
const long request = (long)ihk_mc_syscall_arg0(ctx);
|
||||
@ -2726,6 +2858,10 @@ SYSCALL_DECLARE(ptrace)
|
||||
case PTRACE_ARCH_PRCTL:
|
||||
dkprintf("ptrace: unimplemented ptrace(PTRACE_ARCH_PRCTL) called.\n");
|
||||
break;
|
||||
case PTRACE_GETEVENTMSG:
|
||||
dkprintf("ptrace: PTRACE_GETEVENTMSG: data=%p\n", data);
|
||||
error = ptrace_geteventmsg(pid, data);
|
||||
break;
|
||||
default:
|
||||
dkprintf("ptrace: unimplemented ptrace called.\n");
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user