/* push argv into user stack, returns argc. * note: vm_verify() may override proc's address space, take care. * */ int upush_argv(uint *esp, char **tmp){ uint arglen, argc, tmp_esp; int i,r; char *str, **uargv; argc = 0; if (tmp != NULL) { for (i=0; (str=tmp[i])!=NULL; i++) { arglen += strlen(str)+1; argc++; } } arglen += sizeof(char*) * argc; // note: vm_verify may modify proc's address space. if (vm_verify(*esp-arglen, arglen) < 0){ syserr(EINVAL); return -1; } // push to ustack finally uargv = *esp - arglen; for (i=argc-1; i>=0; i--){ str = tmp[i]; upush(esp, str, strlen(str)+1); uargv[i] = (char *) *esp; } *esp = uargv; // push argv[] upush(esp, &uargv, sizeof(uint)); return argc; }
/* * perform the action specified by the current signal. * the usual sequence is: * if (issig()) * psig(); * */ void psig(){ uint n, esp, usr; struct trap *tf; struct sigaction *sa; struct jmp_buf jbuf, *ujbuf; void *ufunc; n = cu->p_cursig; if (n==0 || n>NSIG) return; cu->p_sig &= ~(1<<(n-1)); sa = &(cu->p_sigact[n-1]); // check blocked signal cu->p_cursig = 0; if (sa->sa_handler != SIG_DFL) { tf = cu->p_trap; // save registers and the old sa_mask usigsav(&jbuf, tf, cu->p_sigmask); // store the new sa_mask if ((sa->sa_flags & SA_NOMASK)==0) { cu->p_sigmask |= sa->sa_mask; } // push to the user stack, with a "shellcode" esp = tf->esp; usr = upush(&esp, (char*)&_usigret, 16); ujbuf = (struct jmp_buf*)upush(&esp, (char*)&jbuf, sizeof(struct jmp_buf)); upush(&esp, (char*)&n, sizeof(uint)); upush(&esp, (char*)&usr, sizeof(uint)); ufunc = sa->sa_handler; if (sa->sa_flags & SA_ONESHOT) { sa->sa_handler = NULL; } _retu((uint)ufunc, esp); return; } // on SIG_DFL switch(n){ // ignored on default case SIGCHLD: case SIGCONT: return; // exited on default case SIGSEGV: printk("seg fault.\n"); case SIGINT: case SIGKILL: default: do_exit(1); } }
/* initialize a new struct vm according to an a.out executable * image. * returns NULL on fail. * the user stack initialized like this: * |--------------- esp * | argc * |--------------- * | argv * |--------------- * | argv[0] "..." * | argv[1] "..." * | ... * | argv[n] "..." * --------------- VM_STACK * note: ignored envp yet. * */ int do_exec(char *path, char **argv){ struct inode *ip; struct buf *bp; struct sigaction *sa; struct ahead *ah; struct page *pg; struct vm *vm; struct vma *vp; struct file *fp; uint bn, fd, argc, esp, nr; char **tmp; ip = namei(path, 0); if (ip==NULL) { return syserr(ENOENT); } // read the first block of file to get the a.out header. bn = bmap(ip, 0, 0); if (bn == 0) { syserr(EINVAL); goto _badf; } bp = bread(ip->i_dev, bn); ah = (struct ahead*)bp->b_data; // check this a.out header. if (ah->a_magic != NMAGIC) { syserr(EINVAL); goto _badf; } // restore the path and argv temporarily tmp = store_argv(path, argv); // dettach the previous address space, and initialize a new one vm = &cu->p_vm; vm_clear(vm); vm_renew(vm, ah, ip); // push arguments to the end of user stack, which always the same address. esp = VM_STACK; argc = upush_argv(&esp, tmp); if (argc<0) panic("exec(): bad mem"); upush(&esp, &argc, sizeof(uint)); // free_argv(tmp); // close all the file descriptors with FD_CLOEXEC for (fd=0; fd<NOFILE; fd++) { fp = cu->p_ofile[fd]; if ((fp!=NULL) && (fp->f_fdflag & FD_CLOEXEC)) { do_close(fd); } } // clear all sigactions for (nr=0; nr<NSIG; nr++){ sa = &cu->p_sigact[nr]; sa->sa_handler = SIG_DFL; sa->sa_mask = 0; sa->sa_flags = 0; sa->sa_restorer = NULL; } // never forget this: brelse(bp); iput(ip); // enter user mode _retu(vm->vm_entry, esp); return 0; _badf: brelse(bp); iput(ip); return -1; }