/* 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>),
/* 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),
/* 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),
/* 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),
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)
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
}
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
* 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
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);
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);