diff options
-rw-r--r-- | src/arch/x86/linux/process.cc | 8 | ||||
-rw-r--r-- | src/sim/syscall_emul.cc | 98 | ||||
-rw-r--r-- | 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<X86Linux64>), /* 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<X86Linux64>), @@ -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<X86Linux32>), /* 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<FDEntry> new_fdep = old_hbfdp->clone(); - auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep); + auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(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<HBFDEntry>((*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<HBFDEntry>((*p->fds)[new_tgt_fd]); + if (new_hbp) + p->fds->closeFDEntry(new_tgt_fd); + new_hbp = std::dynamic_pointer_cast<HBFDEntry>(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<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); + tgt_fds[0] = p->fds->allocFD(rpfd); auto wend = PipeFDEntry::EndType::write; auto wpfd = std::make_shared<PipeFDEntry>(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); |