# Node ID 01d31dbe35c4f5eb0baddccae75812c844a34b3f # Parent 693893fbee1f3b5946b3eaf495bcc1d7812373c7 diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc --- a/src/arch/arm/linux/process.cc +++ b/src/arch/arm/linux/process.cc @@ -162,7 +162,7 @@ /* 38 */ SyscallDesc("rename", renameFunc), /* 39 */ SyscallDesc("mkdir", mkdirFunc), /* 40 */ SyscallDesc("rmdir", unimplementedFunc), - /* 41 */ SyscallDesc("dup", dupFunc), + /* 41 */ SyscallDesc("dup", dupFunc), /* 42 */ SyscallDesc("pipe", pipePseudoFunc), /* 43 */ SyscallDesc("times", timesFunc), /* 44 */ SyscallDesc("unused#44", unimplementedFunc), @@ -513,7 +513,7 @@ /* 20 */ SyscallDesc("epoll_create1", unimplementedFunc), /* 21 */ SyscallDesc("epoll_ctl", unimplementedFunc), /* 22 */ SyscallDesc("epoll_pwait", unimplementedFunc), - /* 23 */ SyscallDesc("dup", dupFunc), + /* 23 */ SyscallDesc("dup", dupFunc), /* 24 */ SyscallDesc("dup3", unimplementedFunc), /* 25 */ SyscallDesc("fcntl64", fcntl64Func), /* 26 */ SyscallDesc("inotify_init1", unimplementedFunc), diff --git a/src/arch/power/linux/process.cc b/src/arch/power/linux/process.cc --- a/src/arch/power/linux/process.cc +++ b/src/arch/power/linux/process.cc @@ -107,7 +107,7 @@ /* 38 */ SyscallDesc("rename", renameFunc), /* 39 */ SyscallDesc("mkdir", unimplementedFunc), /* 40 */ SyscallDesc("rmdir", unimplementedFunc), - /* 41 */ SyscallDesc("dup", dupFunc), + /* 41 */ SyscallDesc("dup", dupFunc), /* 42 */ SyscallDesc("pipe", unimplementedFunc), /* 43 */ SyscallDesc("times", timesFunc), /* 44 */ SyscallDesc("prof", unimplementedFunc), diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc --- a/src/arch/x86/linux/process.cc +++ b/src/arch/x86/linux/process.cc @@ -242,7 +242,7 @@ /* 19 */ SyscallDesc("readv", unimplementedFunc), /* 20 */ SyscallDesc("writev", writevFunc), /* 21 */ SyscallDesc("access", ignoreFunc), - /* 22 */ SyscallDesc("pipe", unimplementedFunc), + /* 22 */ SyscallDesc("pipe", pipeFunc), /* 23 */ SyscallDesc("select", unimplementedFunc), /* 24 */ SyscallDesc("sched_yield", unimplementedFunc), /* 25 */ SyscallDesc("mremap", mremapFunc), @@ -252,8 +252,8 @@ /* 29 */ SyscallDesc("shmget", unimplementedFunc), /* 30 */ SyscallDesc("shmat", unimplementedFunc), /* 31 */ SyscallDesc("shmctl", unimplementedFunc), - /* 32 */ SyscallDesc("dup", dupFunc), - /* 33 */ SyscallDesc("dup2", unimplementedFunc), + /* 32 */ SyscallDesc("dup", dupFunc), + /* 33 */ SyscallDesc("dup2", dup2Func), /* 34 */ SyscallDesc("pause", unimplementedFunc), /* 35 */ SyscallDesc("nanosleep", ignoreFunc, SyscallDesc::WarnOnce), /* 36 */ SyscallDesc("getitimer", unimplementedFunc), @@ -590,8 +590,8 @@ /* 38 */ SyscallDesc("rename", unimplementedFunc), /* 39 */ SyscallDesc("mkdir", unimplementedFunc), /* 40 */ SyscallDesc("rmdir", unimplementedFunc), - /* 41 */ SyscallDesc("dup", dupFunc), - /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 41 */ SyscallDesc("dup", dupFunc), + /* 42 */ SyscallDesc("pipe", pipeFunc), /* 43 */ SyscallDesc("times", timesFunc), /* 44 */ SyscallDesc("prof", unimplementedFunc), /* 45 */ SyscallDesc("brk", brkFunc), @@ -612,7 +612,7 @@ /* 60 */ SyscallDesc("umask", unimplementedFunc), /* 61 */ SyscallDesc("chroot", unimplementedFunc), /* 62 */ SyscallDesc("ustat", unimplementedFunc), - /* 63 */ SyscallDesc("dup2", unimplementedFunc), + /* 63 */ SyscallDesc("dup2", dup2Func), /* 64 */ SyscallDesc("getppid", unimplementedFunc), /* 65 */ SyscallDesc("getpgrp", unimplementedFunc), /* 66 */ SyscallDesc("setsid", unimplementedFunc), diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -223,10 +223,6 @@ SyscallReturn fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc); -/// Target dup() handler. -SyscallReturn dupFunc(SyscallDesc *desc, int num, - Process *process, ThreadContext *tc); - /// Target fcntl64() handler. SyscallReturn fcntl64Func(SyscallDesc *desc, int num, Process *process, ThreadContext *tc); @@ -235,6 +231,14 @@ SyscallReturn setuidFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc); +/// Target pipe() handler. +SyscallReturn pipeFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Internal pipe() handler. +SyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, + ThreadContext *tc, bool pseudoPipe); + /// Target getpid() handler. SyscallReturn getpidFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc); @@ -1689,6 +1693,82 @@ return 0; } +/** + * FIXME: The file description is not shared among file descriptors created + * with dup. Really, it's difficult to maintain fields like file offset or + * flags since an update to such a field won't be reflected in the metadata + * for the fd entries that we maintain for checkpoint restoration. + */ +template +SyscallReturn +dupFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) +{ + int index = 0; + int tgt_fd = process->getSyscallArg(tc, index); + int sim_fd; + + FDEntryPtr old_fdp = process->fds[tgt_fd]; + + if (std::dynamic_pointer_cast(old_fdp) != nullptr) + return -EBADF; + + if (old_fdp == nullptr || (sim_fd = old_fdp->getSimFD()) < 0) + return -EBADF; + + int result = dup(sim_fd); + + if (result == -1) + return -errno; + + FDEntryPtr new_fdp = old_fdp->clone(); + new_fdp->setSimFD(result); + new_fdp->setCOE(false); + + return process->fds.allocFD(new_fdp); +} + +template +SyscallReturn +dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + int index = 0; + int old_tgt_fd = p->getSyscallArg(tc, index); + int new_tgt_fd = p->getSyscallArg(tc, index); + + FDEntryPtr old_fdp = p->fds[old_tgt_fd]; + FDEntryPtr new_fdp = p->fds[new_tgt_fd]; + + if (std::dynamic_pointer_cast(old_fdp) != nullptr) + return -EBADF; + + int old_sim_fd; + if (old_fdp == nullptr || (old_sim_fd = old_fdp->getSimFD()) < 0) + return -EBADF; + + int new_sim_fd = new_fdp->getSimFD(); + + /** + * It's possible that the target will close() the target file descriptor + * on its own before handing the target file descriptor over to dup2; this + * causes the target-host fd mapping to disappear so that a bad file + * descriptor is handed to the system's dup2. Must intervene and create + * a valid host file descriptor to pass to the system's dup2 call. + */ + if (new_sim_fd == -1) + new_sim_fd = open("/dev/null", O_RDONLY); + + int res_fd = dup2(old_sim_fd, new_sim_fd); + + if (res_fd == -1) + return -errno; + + p->fds[new_tgt_fd] = old_fdp->clone(); + p->fds[new_tgt_fd]->setSimFD(res_fd); + p->fds[new_tgt_fd]->setCOE(false); + + return new_tgt_fd; +} + template SyscallReturn execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -219,8 +219,11 @@ int status = 0; if (sim_fd > 2) status = close(sim_fd); - if (status >= 0) - p->fds[tgt_fd] = nullptr; + + if (status == -1) + return -errno; + + p->fds[tgt_fd] = nullptr; return status; } @@ -230,9 +233,9 @@ { int index = 0; int tgt_fd = p->getSyscallArg(tc, index); - Addr bufPtr = p->getSyscallArg(tc, index); + Addr buf_ptr = p->getSyscallArg(tc, index); int nbytes = p->getSyscallArg(tc, index); - BufferArg bufArg(bufPtr, nbytes); + BufferArg bufArg(buf_ptr, nbytes); int sim_fd; FDEntryPtr fdp = p->fds[tgt_fd]; @@ -253,9 +256,9 @@ { int index = 0; int tgt_fd = p->getSyscallArg(tc, index); - Addr bufPtr = p->getSyscallArg(tc, index); + Addr buf_ptr = p->getSyscallArg(tc, index); int nbytes = p->getSyscallArg(tc, index); - BufferArg bufArg(bufPtr, nbytes); + BufferArg bufArg(buf_ptr, nbytes); int sim_fd; FDEntryPtr fdp = p->fds[tgt_fd]; @@ -340,9 +343,9 @@ gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { int index = 0; - Addr bufPtr = p->getSyscallArg(tc, index); + Addr buf_ptr = p->getSyscallArg(tc, index); int name_len = p->getSyscallArg(tc, index); - BufferArg name(bufPtr, name_len); + BufferArg name(buf_ptr, name_len); strncpy((char *)name.bufferPtr(), hostname, name_len); @@ -356,9 +359,9 @@ { int result = 0; int index = 0; - Addr bufPtr = p->getSyscallArg(tc, index); + Addr buf_ptr = p->getSyscallArg(tc, index); unsigned long size = p->getSyscallArg(tc, index); - BufferArg buf(bufPtr, size); + BufferArg buf(buf_ptr, size); // Is current working directory defined? string cwd = p->getcwd(); @@ -402,10 +405,10 @@ // Adjust path for current working directory path = p->fullPath(path); - Addr bufPtr = p->getSyscallArg(tc, index); + Addr buf_ptr = p->getSyscallArg(tc, index); size_t bufsiz = p->getSyscallArg(tc, index); - BufferArg buf(bufPtr, bufsiz); + BufferArg buf(buf_ptr, bufsiz); int result = -1; if (path != "/proc/self/exe") { @@ -648,37 +651,6 @@ } -/** - * TODO: there's a bit more involved here since file descriptors created with - * dup are supposed to share a file description. So, there is a problem with - * maintaining fields like file offset or flags since an update to such a - * field won't be reflected in the metadata for the fd entries that we - * maintain to hold metadata for checkpoint restoration. - */ -SyscallReturn -dupFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) -{ - int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - - FDEntryPtr old_fdp = process->fds[tgt_fd]; - - if (dynamic_pointer_cast(old_fdp) != nullptr) - return -EBADF; - - int sim_fd; - if (old_fdp == nullptr || (sim_fd = old_fdp->getSimFD()) < 0) - return -EBADF; - - int result = dup(sim_fd); - int local_errno = errno; - - FDEntryPtr new_fdp = old_fdp->clone(); - new_fdp->setSimFD(result); - - return (result == -1) ? -local_errno : process->fds.allocFD(new_fdp); -} - SyscallReturn fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { @@ -715,15 +687,20 @@ } SyscallReturn -pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, + bool pseudoPipe) { + Addr tgt_addr = 0; + if (!pseudoPipe) { + int index = 0; + tgt_addr = p->getSyscallArg(tc, index); + } + int sim_fds[2], tgt_fds[2]; int pipe_retval = pipe(sim_fds); - if (pipe_retval < 0) { - return pipe_retval; - } + if (pipe_retval == -1) + return -errno; PipeFDPtr read_pfd; read_pfd = make_shared(sim_fds[0], O_WRONLY, @@ -734,8 +711,8 @@ PipeFDEntry::EndType::write, true); /* Assign the pfds to the fd object and retrieve designated tgt_fds. */ - tgt_fds[0] = process->fds.allocFD(read_pfd); - tgt_fds[1] = process->fds.allocFD(write_pfd); + tgt_fds[0] = p->fds.allocFD(read_pfd); + tgt_fds[1] = p->fds.allocFD(write_pfd); /** * Now patch the read object to record the target file descriptor chosen @@ -743,10 +720,35 @@ */ read_pfd->setPipeReadSource(tgt_fds[1]); - // Alpha Linux convention for pipe() is that fd[0] is returned as - // the return value of the function, and fd[1] is returned in r20. - tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); - return sim_fds[0]; + if (pseudoPipe) { + // Alpha Linux convention for pipe() is that fd[0] is returned as + // the return value of the function, and fd[1] is returned in r20. + tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); + return tgt_fds[0]; + } + + // Copy the target file descriptors into buffer space. + BufferArg tgt_handle(tgt_addr, sizeof(int[2])); + int *buf_ptr = (int*)tgt_handle.bufferPtr(); + buf_ptr[0] = tgt_fds[0]; + buf_ptr[1] = tgt_fds[1]; + + // Copy the buffer space back into the target address space. + tgt_handle.copyOut(tc->getMemProxy()); + return 0; +} + +SyscallReturn +pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + return pipeImpl(desc, callnum, process, tc, true); +} + +SyscallReturn +pipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) +{ + return pipeImpl(desc, callnum, process, tc, false); } SyscallReturn