Add ptrace functions of job-control and signal
Note that a forked process automatically becomes ptraced state in this commit.
This commit is contained in:
committed by
Tomoki Shirasawa
parent
ab89de0de6
commit
dbecaa2fc8
@ -448,6 +448,8 @@ void handle_interrupt(int vector, struct x86_regs *regs)
|
||||
|
||||
check_signal(0, regs);
|
||||
check_need_resched();
|
||||
//kprintf("handle_interrupt,exit\n");
|
||||
//schedule();
|
||||
}
|
||||
|
||||
void gpe_handler(struct x86_regs *regs)
|
||||
|
||||
@ -36,6 +36,12 @@ struct sigaction {
|
||||
sigset_t sa_mask;
|
||||
};
|
||||
|
||||
typedef void __sig_fn_t(int);
|
||||
typedef __sig_fn_t *__sig_handler_t;
|
||||
#define SIG_DFL (__sig_handler_t)0
|
||||
#define SIG_IGN (__sig_handler_t)1
|
||||
#define SIG_ERR (__sig_handler_t)-1
|
||||
|
||||
#define SA_NOCLDSTOP 0x00000001U
|
||||
#define SA_NOCLDWAIT 0x00000002U
|
||||
#define SA_NODEFER 0x40000000U
|
||||
@ -71,16 +77,69 @@ typedef struct siginfo {
|
||||
int si_errno; /* If non-zero, an errno value associated with
|
||||
this signal, as defined in <errno.h>. */
|
||||
int si_code; /* Signal code. */
|
||||
#define SI_USER 0 /* sent by kill, sigsend, raise */
|
||||
#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
||||
#define SI_QUEUE -1 /* sent by sigqueue */
|
||||
#define SI_USER 0 /* sent by kill, sigsend, raise */
|
||||
#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
||||
#define SI_QUEUE -1 /* sent by sigqueue */
|
||||
#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
|
||||
#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change
|
||||
*/
|
||||
#define SI_ASYNCIO -4 /* sent by AIO completion */
|
||||
#define SI_SIGIO -5 /* sent by queued SIGIO */
|
||||
#define SI_TKILL -6 /* sent by tkill system call */
|
||||
#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */
|
||||
#define SI_ASYNCIO -4 /* sent by AIO completion */
|
||||
#define SI_SIGIO -5 /* sent by queued SIGIO */
|
||||
#define SI_TKILL -6 /* sent by tkill system call */
|
||||
#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */
|
||||
|
||||
#define ILL_ILLOPC 1 /* illegal opcode */
|
||||
#define ILL_ILLOPN 2 /* illegal operand */
|
||||
#define ILL_ILLADR 3 /* illegal addressing mode */
|
||||
#define ILL_ILLTRP 4 /* illegal trap */
|
||||
#define ILL_PRVOPC 5 /* privileged opcode */
|
||||
#define ILL_PRVREG 6 /* privileged register */
|
||||
#define ILL_COPROC 7 /* coprocessor error */
|
||||
#define ILL_BADSTK 8 /* internal stack error */
|
||||
|
||||
#define FPE_INTDIV 1 /* integer divide by zero */
|
||||
#define FPE_INTOVF 2 /* integer overflow */
|
||||
#define FPE_FLTDIV 3 /* floating point divide by zero */
|
||||
#define FPE_FLTOVF 4 /* floating point overflow */
|
||||
#define FPE_FLTUND 5 /* floating point underflow */
|
||||
#define FPE_FLTRES 6 /* floating point inexact result */
|
||||
#define FPE_FLTINV 7 /* floating point invalid operation */
|
||||
#define FPE_FLTSUB 8 /* subscript out of range */
|
||||
|
||||
#define SEGV_MAPERR 1 /* address not mapped to object */
|
||||
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
|
||||
|
||||
#define BUS_ADRALN 1 /* invalid address alignment */
|
||||
#define BUS_ADRERR 2 /* non-existant physical address */
|
||||
#define BUS_OBJERR 3 /* object specific hardware error */
|
||||
/* hardware memory error consumed on a machine check: action required */
|
||||
#define BUS_MCEERR_AR 4
|
||||
/* hardware memory error detected in process but not consumed: action optional*/
|
||||
#define BUS_MCEERR_AO 5
|
||||
|
||||
#define TRAP_BRKPT 1 /* process breakpoint */
|
||||
#define TRAP_TRACE 2 /* process trace trap */
|
||||
#define TRAP_BRANCH 3 /* process taken branch trap */
|
||||
#define TRAP_HWBKPT 4 /* hardware breakpoint/watchpoint */
|
||||
|
||||
#define CLD_EXITED 1 /* child has exited */
|
||||
#define CLD_KILLED 2 /* child was killed */
|
||||
#define CLD_DUMPED 3 /* child terminated abnormally */
|
||||
#define CLD_TRAPPED 4 /* traced child has trapped */
|
||||
#define CLD_STOPPED 5 /* child has stopped */
|
||||
#define CLD_CONTINUED 6 /* stopped child has continued */
|
||||
|
||||
#define POLL_IN 1 /* data input available */
|
||||
#define POLL_OUT 2 /* output buffers available */
|
||||
#define POLL_MSG 3 /* input message available */
|
||||
#define POLL_ERR 4 /* i/o error */
|
||||
#define POLL_PRI 5 /* high priority input available */
|
||||
#define POLL_HUP 6 /* device disconnected */
|
||||
|
||||
#define SIGEV_SIGNAL 0 /* notify via signal */
|
||||
#define SIGEV_NONE 1 /* other notification: meaningless */
|
||||
#define SIGEV_THREAD 2 /* deliver via thread creation */
|
||||
#define SIGEV_THREAD_ID 4 /* deliver to thread */
|
||||
|
||||
union {
|
||||
int _pad[__SI_PAD_SIZE];
|
||||
@ -186,4 +245,6 @@ struct signalfd_siginfo {
|
||||
#define SIGUNUSED 31
|
||||
#define SIGRTMIN 32
|
||||
|
||||
#define PTRACE_EVENT_EXEC 4
|
||||
|
||||
#endif /*__HEADER_X86_COMMON_SIGNAL_H*/
|
||||
|
||||
@ -216,13 +216,10 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
||||
rc = regs->rax;
|
||||
}
|
||||
|
||||
if(sig == SIGKILL)
|
||||
terminate(0, sig, (ihk_mc_user_context_t *)regs->rsp);
|
||||
|
||||
irqstate = ihk_mc_spinlock_lock(&proc->sighandler->lock);
|
||||
k = proc->sighandler->action + sig - 1;
|
||||
|
||||
if(k->sa.sa_handler == (void *)1){
|
||||
if(k->sa.sa_handler == SIG_IGN){
|
||||
kfree(pending);
|
||||
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
|
||||
return;
|
||||
@ -249,6 +246,7 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
||||
copy_to_user(proc, &sigsp->sigrc, &rc, sizeof(long))){
|
||||
kfree(pending);
|
||||
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
|
||||
kprintf("do_signal,copy_to_user failed\n");
|
||||
terminate(0, sig, (ihk_mc_user_context_t *)regs->rsp);
|
||||
return;
|
||||
}
|
||||
@ -272,53 +270,129 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
||||
kfree(pending);
|
||||
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
|
||||
}
|
||||
else{
|
||||
else {
|
||||
int coredumped = 0;
|
||||
kfree(pending);
|
||||
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
|
||||
switch(sig){
|
||||
case SIGCHLD:
|
||||
case SIGURG:
|
||||
return;
|
||||
case SIGSTOP: {
|
||||
dkprintf("do_signal,SIGSTOP,changing state\n");
|
||||
struct process *proc = cpu_local_var(current);
|
||||
struct fork_tree_node *ftn = proc->ftn;
|
||||
int exit_code = SIGSTOP;
|
||||
switch (sig) {
|
||||
case SIGSTOP: {
|
||||
dkprintf("do_signal,SIGSTOP,changing state\n");
|
||||
struct process *proc = cpu_local_var(current);
|
||||
struct fork_tree_node *ftn = proc->ftn;
|
||||
|
||||
/* Update process state in fork tree */
|
||||
ihk_mc_spinlock_lock_noirq(&ftn->lock);
|
||||
ftn->exit_status = (exit_code << 8) | 0x7f;
|
||||
ftn->status = PS_STOPPED;
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
/* Update process state in fork tree */
|
||||
ihk_mc_spinlock_lock_noirq(&ftn->lock);
|
||||
ftn->group_exit_status = SIGSTOP;
|
||||
|
||||
/* Wake up the parent who tried wait4 and sleeping */
|
||||
waitq_wakeup(&proc->ftn->parent->waitpid_q);
|
||||
/* Reap and set new signal_flags */
|
||||
ftn->signal_flags = SIGNAL_STOP_STOPPED;
|
||||
|
||||
dkprintf("do_signal,SIGSTOP,sleeping\n");
|
||||
/* Sleep */
|
||||
proc->status = PS_STOPPED;
|
||||
schedule();
|
||||
dkprintf("SIGSTOP(): woken up\n");
|
||||
goto out; }
|
||||
case SIGCONT:
|
||||
dkprintf("do_signal,SIGCONT,do nothing\n");
|
||||
goto out;
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGTRAP:
|
||||
case SIGABRT:
|
||||
case SIGBUS:
|
||||
case SIGFPE:
|
||||
case SIGUSR1:
|
||||
case SIGSEGV:
|
||||
case SIGUSR2:
|
||||
ftn->status = PS_STOPPED;
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
|
||||
/* Wake up the parent who tried wait4 and sleeping */
|
||||
waitq_wakeup(&proc->ftn->parent->waitpid_q);
|
||||
|
||||
dkprintf("do_signal,SIGSTOP,sleeping\n");
|
||||
/* Sleep */
|
||||
proc->status = PS_STOPPED;
|
||||
schedule();
|
||||
dkprintf("SIGSTOP(): woken up\n");
|
||||
break; }
|
||||
case SIGTRAP: {
|
||||
dkprintf("do_signal,SIGTRAP,changing state\n");
|
||||
struct process *proc = cpu_local_var(current);
|
||||
struct fork_tree_node *ftn = proc->ftn;
|
||||
|
||||
/* Update process state in fork tree */
|
||||
ihk_mc_spinlock_lock_noirq(&ftn->lock);
|
||||
ftn->exit_status = SIGTRAP;
|
||||
ftn->status = PS_TRACED;
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
|
||||
/* Wake up the parent who tried wait4 and sleeping */
|
||||
waitq_wakeup(&proc->ftn->parent->waitpid_q);
|
||||
|
||||
dkprintf("do_signal,SIGTRAP,sleeping\n");
|
||||
/* Sleep */
|
||||
proc->status = PS_TRACED;
|
||||
|
||||
//struct cpu_local_var *v = get_this_cpu_local_var();
|
||||
//v->flags |= CPU_FLAG_NEED_RESCHED;
|
||||
|
||||
schedule();
|
||||
dkprintf("SIGTRAP(): woken up\n");
|
||||
break; }
|
||||
case SIGCONT:
|
||||
dkprintf("do_signal,SIGCONT,do nothing\n");
|
||||
break;
|
||||
case SIGSEGV:
|
||||
kprintf("do_signal,SIGSEGV received\n");
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGABRT:
|
||||
case SIGBUS:
|
||||
case SIGFPE:
|
||||
case SIGUSR1:
|
||||
case SIGUSR2:
|
||||
coredump(proc, regs);
|
||||
coredumped = 0x80;
|
||||
terminate(0, sig | coredumped, (ihk_mc_user_context_t *)regs->rsp);
|
||||
break;
|
||||
case SIGKILL:
|
||||
dkprintf("do_signal,calling terminate\n");
|
||||
terminate(0, sig, (ihk_mc_user_context_t *)regs->rsp);
|
||||
break;
|
||||
case SIGCHLD:
|
||||
case SIGURG:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
terminate(0, sig | coredumped, (ihk_mc_user_context_t *)regs->rsp);
|
||||
}
|
||||
out:;
|
||||
}
|
||||
|
||||
static int ptrace_report_signal(struct process *proc, struct sig_pending *pending) {
|
||||
int sig;
|
||||
__sigset_t w;
|
||||
long rc;
|
||||
|
||||
/* Save reason why stopped and process state for wait to reap */
|
||||
for (w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1);
|
||||
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
|
||||
proc->ftn->exit_status = sig;
|
||||
/* Transition process state */
|
||||
proc->ftn->status = PS_TRACED;
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
|
||||
if (proc->ftn->parent) {
|
||||
/* kill SIGCHLD */
|
||||
ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock);
|
||||
if (proc->ftn->parent->owner) {
|
||||
struct siginfo info;
|
||||
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = SIGCHLD;
|
||||
info.si_code = CLD_TRAPPED;
|
||||
info._sifields._sigchld.si_pid = proc->pid;
|
||||
info._sifields._sigchld.si_status = PS_TRACED;
|
||||
rc = do_kill(proc->ftn->parent->owner->pid, -1, SIGCHLD, &info);
|
||||
if (rc < 0) {
|
||||
kprintf("ptrace_report_signal,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);
|
||||
}
|
||||
|
||||
dkprintf("ptrace_report_signal,sleeping\n");
|
||||
/* Sleep */
|
||||
proc->status = PS_TRACED;
|
||||
schedule();
|
||||
dkprintf("ptrace_report_signal,wake up\n");
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
void
|
||||
@ -330,8 +404,9 @@ check_signal(unsigned long rc, void *regs0)
|
||||
struct sig_pending *next;
|
||||
struct list_head *head;
|
||||
ihk_spinlock_t *lock;
|
||||
__sigset_t w;
|
||||
__sigset_t w, sig_bv;
|
||||
int irqstate;
|
||||
int sig;
|
||||
|
||||
if(clv == NULL)
|
||||
return;
|
||||
@ -339,8 +414,9 @@ check_signal(unsigned long rc, void *regs0)
|
||||
if(proc == NULL || proc->pid == 0)
|
||||
return;
|
||||
|
||||
if(regs != NULL && (regs->rsp & 0x8000000000000000))
|
||||
if(regs != NULL && (regs->rsp & 0x8000000000000000)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(;;){
|
||||
w = proc->sigmask.__val[0];
|
||||
@ -372,8 +448,16 @@ check_signal(unsigned long rc, void *regs0)
|
||||
pending = NULL;
|
||||
ihk_mc_spinlock_unlock(lock, irqstate);
|
||||
}
|
||||
if(!pending)
|
||||
if(!pending) {
|
||||
dkprintf("check_signal,queue is empty\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for(sig_bv = pending->sigmask.__val[0], sig = 0; sig_bv; sig++, sig_bv >>= 1);
|
||||
if((proc->ftn->ptrace & PT_TRACED) && sig != SIGKILL) {
|
||||
sig = ptrace_report_signal(proc, pending);
|
||||
/* TODO: Tracing process could overwrite signal, so handle the case here. */
|
||||
}
|
||||
|
||||
do_signal(rc, regs, proc, pending);
|
||||
}
|
||||
@ -382,6 +466,7 @@ check_signal(unsigned long rc, void *regs0)
|
||||
unsigned long
|
||||
do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
{
|
||||
dkprintf("do_kill,pid=%d,tid=%d,sig=%d\n", pid, tid, sig);
|
||||
struct cpu_local_var *v;
|
||||
struct process *p;
|
||||
struct process *proc = cpu_local_var(current);
|
||||
@ -392,7 +477,6 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
struct list_head *head;
|
||||
int rc;
|
||||
unsigned long irqstate = 0;
|
||||
struct k_sigaction *k;
|
||||
int doint;
|
||||
ihk_spinlock_t *savelock = NULL;
|
||||
int found = 0;
|
||||
@ -448,7 +532,6 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
kfree(pids);
|
||||
return rc;
|
||||
}
|
||||
|
||||
irqstate = cpu_disable_interrupt_save();
|
||||
mask = __sigmask(sig);
|
||||
if(tid == -1){
|
||||
@ -464,8 +547,9 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
if(p->tid == pid || tproc == NULL){
|
||||
if(!(mask & p->sigmask.__val[0])){
|
||||
tproc = p;
|
||||
if(!found && savelock)
|
||||
if(!found && savelock) {
|
||||
ihk_mc_spinlock_unlock_noirq(savelock);
|
||||
}
|
||||
found = 1;
|
||||
savelock = &(v->runq_lock);
|
||||
if(savelock0 && savelock0 != savelock){
|
||||
@ -486,8 +570,9 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
if(!found) {
|
||||
ihk_mc_spinlock_unlock_noirq(&(v->runq_lock));
|
||||
}
|
||||
}
|
||||
if(tproc == NULL){
|
||||
tproc = tproc0;
|
||||
@ -553,31 +638,29 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
k = tproc->sighandler->action + sig - 1;
|
||||
if(k->sa.sa_handler != (void *)1 &&
|
||||
(k->sa.sa_handler != NULL ||
|
||||
(sig != SIGCHLD && sig != SIGURG))){
|
||||
pending = NULL;
|
||||
if(sig < 33){ // SIGRTMIN - SIGRTMAX
|
||||
list_for_each_entry(pending, head, list){
|
||||
if(pending->sigmask.__val[0] == mask)
|
||||
break;
|
||||
}
|
||||
if(&pending->list == head)
|
||||
pending = NULL;
|
||||
/* Put signal event even when handler is SIG_IGN or SIG_DFL
|
||||
because target ptraced process must call ptrace_report_signal
|
||||
in check_signal */
|
||||
pending = NULL;
|
||||
if (sig < 33) { // SIGRTMIN - SIGRTMAX
|
||||
list_for_each_entry(pending, head, list){
|
||||
if(pending->sigmask.__val[0] == mask)
|
||||
break;
|
||||
}
|
||||
if(pending == NULL){
|
||||
doint = 1;
|
||||
pending = kmalloc(sizeof(struct sig_pending), IHK_MC_AP_NOWAIT);
|
||||
if(!pending){
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
else{
|
||||
pending->sigmask.__val[0] = mask;
|
||||
memcpy(&pending->info, info, sizeof(siginfo_t));
|
||||
list_add_tail(&pending->list, head);
|
||||
tproc->sigevent = 1;
|
||||
}
|
||||
if(&pending->list == head)
|
||||
pending = NULL;
|
||||
}
|
||||
if(pending == NULL){
|
||||
doint = 1;
|
||||
pending = kmalloc(sizeof(struct sig_pending), IHK_MC_AP_NOWAIT);
|
||||
if(!pending){
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
else{
|
||||
pending->sigmask.__val[0] = mask;
|
||||
memcpy(&pending->info, info, sizeof(siginfo_t));
|
||||
list_add_tail(&pending->list, head);
|
||||
tproc->sigevent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,13 +670,13 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
else{
|
||||
ihk_mc_spinlock_unlock_noirq(&tproc->sigpendinglock);
|
||||
}
|
||||
dkprintf("do_kill,pid=%d,sig=%d\n", pid, sig);
|
||||
|
||||
if(doint && !(mask & tproc->sigmask.__val[0])){
|
||||
dkprintf("do_kill,proc=%p,tproc=%p\n", proc, tproc);
|
||||
switch(sig) {
|
||||
case SIGCONT:
|
||||
break;
|
||||
case SIGSTOP:
|
||||
case SIGKILL:
|
||||
default:
|
||||
if(proc != tproc){
|
||||
dkprintf("do_kill,ipi,pid=%d,cpu_id=%d\n",
|
||||
@ -602,25 +685,32 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ihk_mc_spinlock_unlock_noirq(savelock);
|
||||
cpu_restore_interrupt(irqstate);
|
||||
|
||||
switch(sig) {
|
||||
case SIGSTOP:
|
||||
break;
|
||||
case SIGKILL:
|
||||
#if 0
|
||||
/* Is this really needed? */
|
||||
kprintf("do_kill,sending kill to mcexec,pid=%d,cpuid=%d\n",
|
||||
tproc->pid, tproc->cpu_id);
|
||||
interrupt_syscall(tproc->pid, tproc->cpu_id);
|
||||
#endif
|
||||
break;
|
||||
case SIGCONT:
|
||||
dkprintf("do_kill,SIGCONT\n");
|
||||
/* Wake up the target only when stopped by SIGSTOP */
|
||||
sched_wakeup_process(tproc, PS_STOPPED);
|
||||
ihk_mc_spinlock_lock_noirq(&tproc->ftn->lock);
|
||||
if (tproc->ftn->status & PS_STOPPED) {
|
||||
ihk_mc_spinlock_lock_noirq(&tproc->ftn->lock);
|
||||
xchg4((int *)(&tproc->ftn->status), PS_RUNNING);
|
||||
ihk_mc_spinlock_unlock_noirq(&tproc->ftn->lock);
|
||||
/* Reap and set singal_flags */
|
||||
tproc->ftn->signal_flags = SIGNAL_STOP_CONTINUED;
|
||||
}
|
||||
ihk_mc_spinlock_unlock_noirq(&tproc->ftn->lock);
|
||||
break;
|
||||
case SIGSTOP:
|
||||
default:
|
||||
dkprintf("do_kill,sending kill to mcexec,pid=%d,cpuid=%d\n",
|
||||
tproc->pid, tproc->cpu_id);
|
||||
interrupt_syscall(tproc->pid, tproc->cpu_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,7 +447,7 @@ retry:
|
||||
|
||||
/* Check whether the resolved path is a symlink */
|
||||
if (lstat(path, &sb) == -1) {
|
||||
fprintf(stderr, "lookup_exec_path(): error stat\n");
|
||||
fprintf(stderr, "lookup_exec_path(): %s, error stat\n");
|
||||
return errno;
|
||||
}
|
||||
|
||||
|
||||
@ -362,6 +362,7 @@ static int process_msg_prepare_process(unsigned long rphys)
|
||||
return -ENOMEM;
|
||||
}
|
||||
proc->pid = pn->pid;
|
||||
kprintf("prepare_process,pid=%d,ptrace=%08x\n", proc->pid, proc->ftn->ptrace);
|
||||
proc->pgid = pn->pgid;
|
||||
proc->ftn->pid = pn->pid;
|
||||
proc->vm->region.user_start = pn->user_start;
|
||||
|
||||
@ -55,9 +55,19 @@
|
||||
#define PS_ZOMBIE 0x8
|
||||
#define PS_EXITED 0x10
|
||||
#define PS_STOPPED 0x20
|
||||
#define PS_TRACED 0x40 /* Set to "not running" by a ptrace related event */
|
||||
|
||||
#define PS_NORMAL (PS_INTERRUPTIBLE | PS_UNINTERRUPTIBLE)
|
||||
|
||||
#define PT_TRACED 0x1 /* The process is ptraced */
|
||||
#define PT_TRACE_EXEC 0x2 /* Trace execve(2) */
|
||||
|
||||
#define PTRACE_CONT 7
|
||||
#define PTRACE_KILL 8
|
||||
|
||||
#define SIGNAL_STOP_STOPPED 0x1 /* The process has been stopped by SIGSTOP */
|
||||
#define SIGNAL_STOP_CONTINUED 0x2 /* The process has been resumed by SIGCONT */
|
||||
|
||||
/* Waitpid options */
|
||||
#define WNOHANG 0x00000001
|
||||
#define WUNTRACED 0x00000002
|
||||
@ -154,7 +164,29 @@ struct fork_tree_node {
|
||||
struct list_head children;
|
||||
struct list_head siblings_list;
|
||||
|
||||
/* The ptracing process behave as the parent of the ptraced process
|
||||
after using PTRACE_ATTACH except getppid. So we save it here. */
|
||||
struct fork_tree_node *ppid_parent;
|
||||
|
||||
/* Manage ptraced processes in the separate list to make it easy to
|
||||
restore the orginal parent child relationship when
|
||||
performing PTRACE_DETACH */
|
||||
struct list_head ptrace_children;
|
||||
struct list_head ptrace_siblings_list;
|
||||
|
||||
struct waitq waitpid_q;
|
||||
|
||||
/* Store exit_status for a group of threads when stopped by SIGSTOP.
|
||||
exit_status can't be used because values of exit_status of threads
|
||||
might divert while the threads are exiting by group_exit(). */
|
||||
int group_exit_status;
|
||||
|
||||
/* Showing whether or not the process is ptraced */
|
||||
int ptrace;
|
||||
|
||||
/* Store event related to signal. For example,
|
||||
it represents that the proceess has been resumed by SIGCONT. */
|
||||
int signal_flags;
|
||||
};
|
||||
|
||||
void hold_fork_tree_node(struct fork_tree_node *ftn);
|
||||
|
||||
@ -84,15 +84,25 @@ void init_fork_tree_node(struct fork_tree_node *ftn,
|
||||
/* These will be filled out when changing status */
|
||||
ftn->pid = -1;
|
||||
ftn->exit_status = -1;
|
||||
ftn->group_exit_status = 0;
|
||||
ftn->status = PS_RUNNING;
|
||||
#if 1
|
||||
ftn->ptrace = parent ? PT_TRACED : 0; /*debug*//*takagi*/
|
||||
#endif
|
||||
ftn->signal_flags = 0;
|
||||
|
||||
ftn->parent = NULL;
|
||||
if (parent) {
|
||||
ftn->parent = parent;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&ftn->children);
|
||||
INIT_LIST_HEAD(&ftn->siblings_list);
|
||||
|
||||
if (parent) {
|
||||
ftn->ppid_parent = parent; /*debug*//*takagi*/
|
||||
}
|
||||
INIT_LIST_HEAD(&ftn->ptrace_children);
|
||||
INIT_LIST_HEAD(&ftn->ptrace_siblings_list);
|
||||
|
||||
waitq_init(&ftn->waitpid_q);
|
||||
}
|
||||
@ -287,6 +297,12 @@ struct process *clone_process(struct process *org, unsigned long pc,
|
||||
list_add_tail(&proc->ftn->siblings_list, &org->ftn->children);
|
||||
ihk_mc_spinlock_unlock_noirq(&org->ftn->lock);
|
||||
|
||||
/*takagi*//*debug*/
|
||||
#if 1
|
||||
ihk_mc_spinlock_lock_noirq(&org->ftn->lock);
|
||||
list_add_tail(&proc->ftn->ptrace_siblings_list, &org->ftn->ptrace_children);
|
||||
ihk_mc_spinlock_unlock_noirq(&org->ftn->lock);
|
||||
#endif
|
||||
/* We hold a reference to parent */
|
||||
hold_fork_tree_node(proc->ftn->parent);
|
||||
|
||||
@ -1927,10 +1943,10 @@ redo:
|
||||
void check_need_resched(void)
|
||||
{
|
||||
struct cpu_local_var *v = get_this_cpu_local_var();
|
||||
if (v->flags & CPU_FLAG_NEED_RESCHED) {
|
||||
if (v->flags & CPU_FLAG_NEED_RESCHED) {
|
||||
v->flags &= ~CPU_FLAG_NEED_RESCHED;
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1940,11 +1956,14 @@ int sched_wakeup_process(struct process *proc, int valid_states)
|
||||
int spin_slept = 0;
|
||||
unsigned long irqstate;
|
||||
struct cpu_local_var *v = get_cpu_local_var(proc->cpu_id);
|
||||
|
||||
dkprintf("sched_wakeup_process,proc->pid=%d,valid_states=%08x,proc->status=%08x,proc->cpu_id=%d,my cpu_id=%d\n",
|
||||
proc->pid, valid_states, proc->status, proc->cpu_id, ihk_mc_get_processor_id());
|
||||
|
||||
irqstate = ihk_mc_spinlock_lock(&(proc->spin_sleep_lock));
|
||||
if (proc->spin_sleep) {
|
||||
dkprintf("sched_wakeup_process() spin wakeup: cpu_id: %d\n",
|
||||
proc->cpu_id);
|
||||
proc->cpu_id);
|
||||
|
||||
spin_slept = 1;
|
||||
proc->spin_sleep = 0;
|
||||
@ -1952,8 +1971,9 @@ int sched_wakeup_process(struct process *proc, int valid_states)
|
||||
}
|
||||
ihk_mc_spinlock_unlock(&(proc->spin_sleep_lock), irqstate);
|
||||
|
||||
if (spin_slept)
|
||||
if (spin_slept) {
|
||||
return status;
|
||||
}
|
||||
|
||||
irqstate = ihk_mc_spinlock_lock(&(v->runq_lock));
|
||||
|
||||
@ -1968,6 +1988,8 @@ int sched_wakeup_process(struct process *proc, int valid_states)
|
||||
ihk_mc_spinlock_unlock(&(v->runq_lock), irqstate);
|
||||
|
||||
if (!status && (proc->cpu_id != ihk_mc_get_processor_id())) {
|
||||
dkprintf("sched_wakeup_process,issuing IPI,proc->cpu_id=%d\n",
|
||||
proc->cpu_id);
|
||||
ihk_mc_interrupt_cpu(get_x86_cpu_local_variable(proc->cpu_id)->apic_id,
|
||||
0xd1);
|
||||
}
|
||||
|
||||
404
kernel/syscall.c
404
kernel/syscall.c
@ -297,13 +297,92 @@ void sigchld_parent(struct process *parent, int status)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int wait_zombie(struct process *proc, struct fork_tree_node *child, int *status, ihk_mc_user_context_t *ctx) {
|
||||
int ret;
|
||||
struct syscall_request request IHK_DMA_ALIGN;
|
||||
|
||||
dkprintf("wait: found PS_ZOMBIE process: %d\n", child->pid);
|
||||
|
||||
list_del(&child->siblings_list);
|
||||
|
||||
if (status) {
|
||||
*status = child->exit_status;
|
||||
}
|
||||
|
||||
release_fork_tree_node(child);
|
||||
|
||||
/* Ask host to clean up exited child */
|
||||
request.number = __NR_wait4;
|
||||
request.args[0] = child->pid;
|
||||
request.args[1] = 0;
|
||||
ret = do_syscall(&request, ctx, ihk_mc_get_processor_id(), 0);
|
||||
|
||||
if (ret != child->pid)
|
||||
kprintf("WARNING: host waitpid failed?\n");
|
||||
dkprintf("wait_zombie,child->pid=%d,status=%08x\n",
|
||||
child->pid, status ? *status : -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wait_stopped(struct process *proc, struct fork_tree_node *child, int *status, int options) {
|
||||
dkprintf("wait_stopped,proc->pid=%d,child->pid=%d,options=%08x\n",
|
||||
proc->pid, child->pid, options);
|
||||
int ret;
|
||||
|
||||
/* Copy exit_status created in do_signal */
|
||||
int *exit_status = (child->ptrace & PT_TRACED) ?
|
||||
&child->exit_status :
|
||||
&child->group_exit_status;
|
||||
|
||||
/* Skip this process because exit_status has been reaped. */
|
||||
if (!*exit_status) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* TODO: define 0x7f in kernel/include/process.h */
|
||||
if (status) {
|
||||
*status = (*exit_status << 8) | 0x7f;
|
||||
}
|
||||
|
||||
/* Reap exit_status. signal_flags is reaped on receiving signal
|
||||
in do_kill(). */
|
||||
if(!(options & WNOWAIT)) {
|
||||
*exit_status = 0;
|
||||
}
|
||||
|
||||
dkprintf("wait_stopped,child->pid=%d,status=%08x\n",
|
||||
child->pid, status ? *status : -1);
|
||||
ret = child->pid;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wait_continued(struct process *proc, struct fork_tree_node *child, int *status, int options) {
|
||||
int ret;
|
||||
|
||||
if (status) {
|
||||
*status = 0xffff;
|
||||
}
|
||||
|
||||
/* Reap signal_flags */
|
||||
if(!(options & WNOWAIT)) {
|
||||
child->signal_flags &= ~SIGNAL_STOP_CONTINUED;
|
||||
}
|
||||
|
||||
dkprintf("wait4,SIGNAL_STOP_CONTINUED,pid=%d,status=%08x\n",
|
||||
child->pid, status ? *status : -1);
|
||||
ret = child->pid;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* From glibc: INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL);
|
||||
*/
|
||||
SYSCALL_DECLARE(wait4)
|
||||
{
|
||||
struct process *proc = cpu_local_var(current);
|
||||
struct fork_tree_node *child, *child_iter;
|
||||
struct fork_tree_node *child_iter;
|
||||
int pid = (int)ihk_mc_syscall_arg0(ctx);
|
||||
int pgid = proc->pgid;
|
||||
int *status = (int *)ihk_mc_syscall_arg1(ctx);
|
||||
@ -312,18 +391,17 @@ SYSCALL_DECLARE(wait4)
|
||||
struct waitq_entry waitpid_wqe;
|
||||
int empty = 1;
|
||||
|
||||
dkprintf("wait4,proc->pid=%d,pid=%d\n", proc->pid, pid);
|
||||
if (options & ~(WNOHANG | WUNTRACED | WCONTINUED)) {
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
rescan:
|
||||
child = NULL;
|
||||
pid = (int)ihk_mc_syscall_arg0(ctx);
|
||||
|
||||
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
|
||||
|
||||
list_for_each_entry(child_iter, &proc->ftn->children, siblings_list) {
|
||||
|
||||
empty = 0;
|
||||
|
||||
ihk_mc_spinlock_lock_noirq(&child_iter->lock);
|
||||
|
||||
@ -331,73 +409,91 @@ rescan:
|
||||
pid == -1 ||
|
||||
(pid == 0 && pgid == child_iter->pgid) ||
|
||||
(pid > 0 && pid == child_iter->pid)) {
|
||||
child = child_iter;
|
||||
break;
|
||||
|
||||
empty = 0;
|
||||
|
||||
if(child_iter->status == PS_ZOMBIE) {
|
||||
ret = wait_zombie(proc, child_iter, status, ctx);
|
||||
if(ret) {
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
|
||||
if((child_iter->signal_flags & SIGNAL_STOP_STOPPED) &&
|
||||
(options & WUNTRACED)) {
|
||||
/* Not ptraced and in stopped state and WUNTRACED is specified */
|
||||
ret = wait_stopped(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
|
||||
if((child_iter->signal_flags & SIGNAL_STOP_CONTINUED) &&
|
||||
(options & WCONTINUED)) {
|
||||
ret = wait_continued(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ihk_mc_spinlock_unlock_noirq(&child_iter->lock);
|
||||
}
|
||||
|
||||
if (empty || (!child && pid != -1)) {
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
return -ECHILD;
|
||||
}
|
||||
|
||||
/* If child is valid we are still holding its ftn->lock */
|
||||
if (child) {
|
||||
if (child->status == PS_ZOMBIE) {
|
||||
struct syscall_request request IHK_DMA_ALIGN;
|
||||
list_for_each_entry(child_iter, &proc->ftn->ptrace_children, ptrace_siblings_list) {
|
||||
|
||||
ihk_mc_spinlock_unlock_noirq(&child->lock);
|
||||
dkprintf("wait: found PS_ZOMBIE process: %d\n", child->pid);
|
||||
ihk_mc_spinlock_lock_noirq(&child_iter->lock);
|
||||
|
||||
if ((pid < 0 && -pid == child_iter->pgid) ||
|
||||
pid == -1 ||
|
||||
(pid == 0 && pgid == child_iter->pgid) ||
|
||||
(pid > 0 && pid == child_iter->pid)) {
|
||||
|
||||
list_del(&child->siblings_list);
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
empty = 0;
|
||||
|
||||
if (status) {
|
||||
*status = child->exit_status;
|
||||
}
|
||||
pid = child->pid;
|
||||
if(child_iter->status == PS_ZOMBIE) {
|
||||
ret = wait_zombie(proc, child_iter, status, ctx);
|
||||
if(ret) {
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
|
||||
release_fork_tree_node(child);
|
||||
if(child_iter->status & (PS_STOPPED | PS_TRACED)) {
|
||||
/* ptraced and in stopeed or trace-stopped state */
|
||||
ret = wait_stopped(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
goto out_found;
|
||||
}
|
||||
} else {
|
||||
/* ptraced and in running or sleeping state */
|
||||
}
|
||||
|
||||
/* Ask host to clean up exited child */
|
||||
request.number = __NR_wait4;
|
||||
request.args[0] = pid;
|
||||
request.args[1] = 0;
|
||||
ret = do_syscall(&request, ctx, ihk_mc_get_processor_id(), 0);
|
||||
|
||||
if (ret != pid)
|
||||
kprintf("WARNING: host waitpid failed?\n");
|
||||
|
||||
goto exit;
|
||||
} else if(child->status == PS_STOPPED) {
|
||||
ihk_mc_spinlock_unlock_noirq(&child->lock);
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
|
||||
/* exit_status is created in do_signal */
|
||||
if (status) {
|
||||
*status = child->exit_status;
|
||||
}
|
||||
pid = child->pid;
|
||||
dkprintf("wait4,PS_STOPPED,pid=%d,status=%08x\n", pid, *status);
|
||||
|
||||
goto exit;
|
||||
if((child_iter->signal_flags & SIGNAL_STOP_CONTINUED) &&
|
||||
(options & WCONTINUED)) {
|
||||
ret = wait_continued(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ihk_mc_spinlock_unlock_noirq(&child->lock);
|
||||
ihk_mc_spinlock_unlock_noirq(&child_iter->lock);
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
ret = -ECHILD;
|
||||
goto out_notfound;
|
||||
}
|
||||
|
||||
/* Don't sleep if WNOHANG requested */
|
||||
if (options & WNOHANG) {
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
|
||||
*status = 0;
|
||||
pid = 0;
|
||||
goto exit;
|
||||
ret = 0;
|
||||
goto out_notfound;
|
||||
}
|
||||
|
||||
/* Sleep */
|
||||
dkprintf("wait4,sleeping\n");
|
||||
waitq_init_entry(&waitpid_wqe, proc);
|
||||
waitq_prepare_to_wait(&proc->ftn->waitpid_q, &waitpid_wqe, PS_INTERRUPTIBLE);
|
||||
|
||||
@ -409,9 +505,14 @@ rescan:
|
||||
waitq_finish_wait(&proc->ftn->waitpid_q, &waitpid_wqe);
|
||||
|
||||
goto rescan;
|
||||
|
||||
exit:
|
||||
return pid;
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
out_found:
|
||||
ihk_mc_spinlock_unlock_noirq(&child_iter->lock);
|
||||
out_notfound:
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
void
|
||||
@ -421,6 +522,8 @@ terminate(int rc, int sig, ihk_mc_user_context_t *ctx)
|
||||
struct process *proc = cpu_local_var(current);
|
||||
struct fork_tree_node *ftn = proc->ftn;
|
||||
struct fork_tree_node *child, *next;
|
||||
struct process *parent_owner;
|
||||
int error;
|
||||
|
||||
request.number = __NR_exit_group;
|
||||
request.args[0] = ((rc & 0x00ff) << 8) | (sig & 0xff);
|
||||
@ -439,17 +542,18 @@ terminate(int rc, int sig, ihk_mc_user_context_t *ctx)
|
||||
/* Do a "wait" on all children and detach owner process */
|
||||
ihk_mc_spinlock_lock_noirq(&ftn->lock);
|
||||
list_for_each_entry_safe(child, next, &ftn->children, siblings_list) {
|
||||
|
||||
list_del(&child->siblings_list);
|
||||
release_fork_tree_node(child);
|
||||
}
|
||||
|
||||
ftn->owner = NULL;
|
||||
|
||||
ihk_mc_spinlock_unlock_noirq(&ftn->lock);
|
||||
|
||||
/* Send SIGCHILD to parent */
|
||||
if (ftn->parent) {
|
||||
int parent_owner_pid;
|
||||
|
||||
dkprintf("terminate,ftn->parent->owner->pid=%d\n",
|
||||
ftn->parent->owner->pid);
|
||||
|
||||
ihk_mc_spinlock_lock_noirq(&ftn->lock);
|
||||
ftn->pid = proc->pid;
|
||||
@ -457,27 +561,38 @@ terminate(int rc, int sig, ihk_mc_user_context_t *ctx)
|
||||
ftn->status = PS_ZOMBIE;
|
||||
ihk_mc_spinlock_unlock_noirq(&ftn->lock);
|
||||
|
||||
/* Wake parent (if sleeping in wait4()) */
|
||||
dkprintf("terminate,wakeup\n");
|
||||
waitq_wakeup(&ftn->parent->waitpid_q);
|
||||
|
||||
/* Signal parent if still attached */
|
||||
ihk_mc_spinlock_lock_noirq(&ftn->parent->lock);
|
||||
if (ftn->parent->owner) {
|
||||
parent_owner = ftn->parent->owner;
|
||||
parent_owner_pid = parent_owner ? ftn->parent->owner->pid : 0;
|
||||
ihk_mc_spinlock_unlock_noirq(&ftn->parent->lock);
|
||||
if (parent_owner) {
|
||||
struct siginfo info;
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = SIGCHLD;
|
||||
info.si_code = sig? ((sig & 0x80)? 3: 2): 1;
|
||||
info.si_code = sig? ((sig & 0x80)? CLD_DUMPED: CLD_KILLED): CLD_EXITED;
|
||||
info._sifields._sigchld.si_pid = proc->pid;
|
||||
info._sifields._sigchld.si_status = ((rc & 0x00ff) << 8) | (sig & 0xff);
|
||||
do_kill(ftn->parent->owner->pid, -1, SIGCHLD, &info);
|
||||
dkprintf("terminate,kill SIGCHLD,target pid=%d\n",
|
||||
parent_owner_pid);
|
||||
error = do_kill(ftn->parent->owner->pid, -1, SIGCHLD, &info);
|
||||
/*
|
||||
sigchld_parent(ftn->parent->owner, 0);
|
||||
*/
|
||||
dkprintf("terminate,klll SIGCHILD,error=%d\n",
|
||||
error);
|
||||
}
|
||||
ihk_mc_spinlock_unlock_noirq(&ftn->parent->lock);
|
||||
|
||||
/* Wake parent (if sleeping in wait4()) */
|
||||
waitq_wakeup(&ftn->parent->waitpid_q);
|
||||
|
||||
|
||||
release_fork_tree_node(ftn->parent);
|
||||
}
|
||||
} else {
|
||||
ihk_mc_spinlock_lock_noirq(&ftn->lock);
|
||||
ftn->status = PS_EXITED;
|
||||
ihk_mc_spinlock_unlock_noirq(&ftn->lock);
|
||||
}
|
||||
|
||||
release_fork_tree_node(ftn);
|
||||
|
||||
@ -490,6 +605,7 @@ terminate(int rc, int sig, ihk_mc_user_context_t *ctx)
|
||||
void
|
||||
interrupt_syscall(int pid, int cpuid)
|
||||
{
|
||||
dkprintf("interrupt_syscall,target pid=%d,target cpuid=%d\n", pid, cpuid);
|
||||
ihk_mc_user_context_t ctx;
|
||||
long lerror;
|
||||
|
||||
@ -509,6 +625,7 @@ SYSCALL_DECLARE(exit_group)
|
||||
SYSCALL_HEADER;
|
||||
#endif
|
||||
|
||||
dkprintf("sys_exit_group,pid=%d\n", cpu_local_var(current)->pid);
|
||||
terminate((int)ihk_mc_syscall_arg0(ctx), 0, ctx);
|
||||
#if 0
|
||||
struct process *proc = cpu_local_var(current);
|
||||
@ -1247,8 +1364,58 @@ SYSCALL_DECLARE(arch_prctl)
|
||||
ihk_mc_syscall_arg1(ctx));
|
||||
}
|
||||
|
||||
static int ptrace_report_exec(struct process *proc) {
|
||||
int error = 0;
|
||||
long rc;
|
||||
struct siginfo info;
|
||||
|
||||
if (!(proc->ftn->ptrace & PT_TRACE_EXEC)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Save reason why stopped and process state for wait to reap */
|
||||
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = SIGTRAP;
|
||||
info.si_code = TRAP_TRACE;
|
||||
proc->ftn->exit_status = (SIGTRAP | (PTRACE_EVENT_EXEC << 8));
|
||||
/* Transition process state */
|
||||
proc->ftn->status = PS_TRACED;
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
|
||||
/* Signal myself so that my parent can wait for me */
|
||||
rc = do_kill(proc->ftn->pid, -1, SIGTRAP, &info);
|
||||
if (rc < 0) {
|
||||
kprintf("ptrace_report_exec,do_kill failed\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->pid;
|
||||
info._sifields._sigchld.si_status = PS_TRACED;
|
||||
rc = do_kill(proc->ftn->parent->owner->pid, -1, SIGCHLD, &info);
|
||||
if(rc < 0) {
|
||||
kprintf("ptrace_report_exec,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);
|
||||
}
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(execve)
|
||||
{
|
||||
int error;
|
||||
long ret;
|
||||
char *empty_envp[1] = {NULL};
|
||||
const char *filename = (const char *)ihk_mc_syscall_arg0(ctx);
|
||||
@ -1363,6 +1530,11 @@ SYSCALL_DECLARE(execve)
|
||||
panic("");
|
||||
}
|
||||
|
||||
error = ptrace_report_exec(cpu_local_var(current));
|
||||
if(error) {
|
||||
kprintf("execve(): ERROR: ptrace_report_exec()\n");
|
||||
}
|
||||
|
||||
/* Switch to new execution context */
|
||||
dkprintf("execve(): switching to new process\n");
|
||||
|
||||
@ -1414,7 +1586,6 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||
else {
|
||||
request1.number = __NR_fork;
|
||||
new->pid = do_syscall(&request1, &ctx1, ihk_mc_get_processor_id(), 0);
|
||||
|
||||
if (new->pid == -1) {
|
||||
kprintf("ERROR: forking host process\n");
|
||||
|
||||
@ -1521,13 +1692,17 @@ SYSCALL_DECLARE(kill)
|
||||
int sig = ihk_mc_syscall_arg1(ctx);
|
||||
struct process *proc = cpu_local_var(current);
|
||||
struct siginfo info;
|
||||
int error;
|
||||
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = sig;
|
||||
info.si_code = SI_USER;
|
||||
info._sifields._kill.si_pid = proc->pid;
|
||||
|
||||
return do_kill(pid, -1, sig, &info);
|
||||
dkprintf("sys_kill,enter,pid=%d,sig=%d\n", pid, sig);
|
||||
error = do_kill(pid, -1, sig, &info);
|
||||
dkprintf("sys_kill,returning,pid=%d,sig=%d,error=%d\n", pid, sig, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
// see linux-2.6.34.13/kernel/signal.c
|
||||
@ -2038,6 +2213,7 @@ SYSCALL_DECLARE(futex)
|
||||
SYSCALL_DECLARE(exit)
|
||||
{
|
||||
struct process *proc = cpu_local_var(current);
|
||||
dkprintf("sys_exit,pid=%d\n", proc->pid);
|
||||
|
||||
#ifdef DCFA_KMOD
|
||||
do_mod_exit((int)ihk_mc_syscall_arg0(ctx));
|
||||
@ -2101,15 +2277,93 @@ SYSCALL_DECLARE(getrlimit)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ptrace_wakeup_sig(int pid, long request, long data) {
|
||||
dkprintf("ptrace_wakeup_sig,pid=%d,data=%08x\n", pid, data);
|
||||
int error;
|
||||
struct process *child;
|
||||
ihk_spinlock_t *savelock;
|
||||
unsigned long irqstate;
|
||||
struct siginfo info;
|
||||
|
||||
child = findthread_and_lock(pid, -1, &savelock, &irqstate);
|
||||
if (!child) {
|
||||
error = -ESRCH;
|
||||
goto out;
|
||||
}
|
||||
ihk_mc_spinlock_unlock(savelock, irqstate);
|
||||
|
||||
error = sched_wakeup_process(child, PS_TRACED);
|
||||
if (error < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ihk_mc_spinlock_lock_noirq(&child->ftn->lock);
|
||||
child->ftn->exit_status = data;
|
||||
if (child->ftn->status & PS_TRACED) {
|
||||
xchg4((int *)(&child->ftn->status), PS_RUNNING);
|
||||
}
|
||||
ihk_mc_spinlock_unlock_noirq(&child->ftn->lock);
|
||||
|
||||
|
||||
if (data > 64 || data < 0) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
case PTRACE_KILL:
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = SIGKILL;
|
||||
error = do_kill(pid, -1, SIGKILL, &info);
|
||||
if (error < 0) {
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case PTRACE_CONT:
|
||||
if(data != 0) {
|
||||
struct process *proc;
|
||||
|
||||
/* TODO: Tracing process replace the original
|
||||
signal with "data" */
|
||||
proc = cpu_local_var(current);
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = data;
|
||||
info.si_code = SI_USER;
|
||||
info._sifields._kill.si_pid = proc->pid;
|
||||
error = do_kill(pid, -1, data, &info);
|
||||
if (error < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(ptrace)
|
||||
{
|
||||
const int request = ihk_mc_syscall_arg0(ctx);
|
||||
const long pid = ihk_mc_syscall_arg1(ctx);
|
||||
void * const addr = (void *)ihk_mc_syscall_arg2(ctx);
|
||||
void * const data = (void *)ihk_mc_syscall_arg3(ctx);
|
||||
const long request = (long)ihk_mc_syscall_arg0(ctx);
|
||||
const int pid = (int)ihk_mc_syscall_arg1(ctx);
|
||||
const long addr = (long)ihk_mc_syscall_arg2(ctx);
|
||||
const long data = (long)ihk_mc_syscall_arg3(ctx);
|
||||
int error;
|
||||
|
||||
kprintf("ptrace(%d,%ld,%p,%p): ENOSYS\n", request, pid, addr, data);
|
||||
return -ENOSYS;
|
||||
switch(request) {
|
||||
case PTRACE_KILL:
|
||||
case PTRACE_CONT:
|
||||
error = ptrace_wakeup_sig(pid, request, data);
|
||||
break;
|
||||
default:
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
dkprintf("ptrace(%d,%ld,%p,%p): returning %d\n", request, pid, addr, data, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
#define MIN2(x,y) (x) < (y) ? (x) : (y)
|
||||
|
||||
Reference in New Issue
Block a user