From 198c515b970604df600c2b84ddfc51fa24ed9754 Mon Sep 17 00:00:00 2001 From: Brandon Potter Date: Wed, 1 Mar 2017 13:35:02 -0600 Subject: syscall-emul: Add or extend dup, dup2, and pipe This changeset extends the pipe system call to work with architectures other than Alpha (and enables the syscall for x86). For the dup system call, it sets the clone-on-exec flag by default. For the dup2 system call, the changeset adds an implementation (and enables it for x86). Change-Id: I00ddb416744ee7dd61a5cd02c4c3d97f30543878 Reviewed-on: https://gem5-review.googlesource.com/2266 Maintainer: Jason Lowe-Power Reviewed-by: Tony Gutierrez Reviewed-by: Michael LeBeane --- src/arch/x86/linux/process.cc | 8 ++-- src/sim/syscall_emul.cc | 98 ++++++++++++++++++++++++++++++++++--------- src/sim/syscall_emul.hh | 12 ++++++ 3 files changed, 95 insertions(+), 23 deletions(-) diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc index f90022bdd..aad5151f6 100644 --- a/src/arch/x86/linux/process.cc +++ b/src/arch/x86/linux/process.cc @@ -242,7 +242,7 @@ static SyscallDesc syscallDescs64[] = { /* 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), @@ -253,7 +253,7 @@ static SyscallDesc syscallDescs64[] = { /* 30 */ SyscallDesc("shmat", unimplementedFunc), /* 31 */ SyscallDesc("shmctl", unimplementedFunc), /* 32 */ SyscallDesc("dup", dupFunc), - /* 33 */ SyscallDesc("dup2", unimplementedFunc), + /* 33 */ SyscallDesc("dup2", dup2Func), /* 34 */ SyscallDesc("pause", unimplementedFunc), /* 35 */ SyscallDesc("nanosleep", ignoreFunc, SyscallDesc::WarnOnce), /* 36 */ SyscallDesc("getitimer", unimplementedFunc), @@ -591,7 +591,7 @@ static SyscallDesc syscallDescs32[] = { /* 39 */ SyscallDesc("mkdir", unimplementedFunc), /* 40 */ SyscallDesc("rmdir", unimplementedFunc), /* 41 */ SyscallDesc("dup", dupFunc), - /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipeFunc), /* 43 */ SyscallDesc("times", timesFunc), /* 44 */ SyscallDesc("prof", unimplementedFunc), /* 45 */ SyscallDesc("brk", brkFunc), @@ -612,7 +612,7 @@ static SyscallDesc syscallDescs32[] = { /* 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.cc b/src/sim/syscall_emul.cc index 968019323..1441592a8 100644 --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -626,13 +626,11 @@ fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) return (result == -1) ? -errno : result; } - /** - * 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. + * 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. */ SyscallReturn dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) @@ -646,13 +644,44 @@ dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) int sim_fd = old_hbfdp->getSimFD(); int result = dup(sim_fd); - int local_errno = errno; + if (result == -1) + return -errno; - std::shared_ptr new_fdep = old_hbfdp->clone(); - auto new_hbfdp = std::dynamic_pointer_cast(new_fdep); + auto new_hbfdp = std::dynamic_pointer_cast(old_hbfdp->clone()); new_hbfdp->setSimFD(result); + new_hbfdp->setCOE(false); + return p->fds->allocFD(new_hbfdp); +} + +SyscallReturn +dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + int index = 0; + + int old_tgt_fd = p->getSyscallArg(tc, index); + auto old_hbp = std::dynamic_pointer_cast((*p->fds)[old_tgt_fd]); + if (!old_hbp) + return -EBADF; + int old_sim_fd = old_hbp->getSimFD(); - return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep); + /** + * We need a valid host file descriptor number to be able to pass into + * the second parameter for dup2 (newfd), but we don't know what the + * viable numbers are; we execute the open call to retrieve one. + */ + int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY)); + if (res_fd == -1) + return -errno; + + int new_tgt_fd = p->getSyscallArg(tc, index); + auto new_hbp = std::dynamic_pointer_cast((*p->fds)[new_tgt_fd]); + if (new_hbp) + p->fds->closeFDEntry(new_tgt_fd); + new_hbp = std::dynamic_pointer_cast(old_hbp->clone()); + new_hbp->setSimFD(res_fd); + new_hbp->setCOE(false); + + return p->fds->allocFD(new_hbp); } SyscallReturn @@ -731,23 +760,28 @@ fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) } 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; auto rend = PipeFDEntry::EndType::read; auto rpfd = std::make_shared(sim_fds[0], O_WRONLY, rend); + tgt_fds[0] = p->fds->allocFD(rpfd); auto wend = PipeFDEntry::EndType::write; auto wpfd = std::make_shared(sim_fds[1], O_RDONLY, wend); - - tgt_fds[0] = process->fds->allocFD(rpfd); - tgt_fds[1] = process->fds->allocFD(wpfd); + tgt_fds[1] = p->fds->allocFD(wpfd); /** * Now patch the read object to record the target file descriptor chosen @@ -759,8 +793,34 @@ pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, * 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) { + tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); + return tgt_fds[0]; + } + + /** + * Copy the target file descriptors into buffer space and then copy + * the buffer space back into the target address 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]; + 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 diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index d379bbe85..d75841cc6 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -241,6 +241,10 @@ SyscallReturn fchownFunc(SyscallDesc *desc, int num, SyscallReturn dupFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc); +/// Target dup2() handler. +SyscallReturn dup2Func(SyscallDesc *desc, int num, + Process *process, ThreadContext *tc); + /// Target fcntl() handler. SyscallReturn fcntlFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc); @@ -253,6 +257,14 @@ SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 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); -- cgit v1.2.3