e7efbaa0edd9643963f93fcbe099c0577d180ade
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Authors: Steve Reinhardt
32 #include "sim/syscall_emul.hh"
35 #include <sys/syscall.h>
42 #include <unordered_map>
44 #include "arch/utility.hh"
45 #include "base/chunk_generator.hh"
46 #include "base/trace.hh"
47 #include "config/the_isa.hh"
48 #include "cpu/thread_context.hh"
49 #include "dev/net/dist_iface.hh"
50 #include "mem/page_table.hh"
51 #include "sim/byteswap.hh"
52 #include "sim/process.hh"
53 #include "sim/sim_exit.hh"
54 #include "sim/syscall_debug_macros.hh"
55 #include "sim/syscall_desc.hh"
56 #include "sim/system.hh"
59 using namespace TheISA
;
62 warnUnsupportedOS(std::string syscall_name
)
64 warn("Cannot invoke %s on host operating system.", syscall_name
);
68 unimplementedFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
70 fatal("syscall %s (#%d) unimplemented.", desc
->name(), callnum
);
77 ignoreFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
79 warn("ignoring syscall %s(...)", desc
->name());
84 ignoreWarnOnceFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
)
86 static std::unordered_map
<SyscallDesc
*, bool> bool_map
;
88 bool &warned
= bool_map
[desc
];
90 warn("ignoring syscall %s(...)\n"
91 " (further warnings will be suppressed)", desc
->name());
99 exitFutexWake(ThreadContext
*tc
, Addr addr
, uint64_t tgid
)
101 // Clear value at address pointed to by thread's childClearTID field.
102 BufferArg
ctidBuf(addr
, sizeof(long));
103 long *ctid
= (long *)ctidBuf
.bufferPtr();
105 ctidBuf
.copyOut(tc
->getVirtProxy());
107 FutexMap
&futex_map
= tc
->getSystemPtr()->futexMap
;
108 // Wake one of the waiting threads.
109 futex_map
.wakeup(addr
, tgid
, 1);
113 exitImpl(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
, bool group
,
116 auto p
= tc
->getProcessPtr();
118 System
*sys
= tc
->getSystemPtr();
121 *p
->exitGroup
= true;
123 if (p
->childClearTID
)
124 exitFutexWake(tc
, p
->childClearTID
, p
->tgid());
126 bool last_thread
= true;
127 Process
*parent
= nullptr, *tg_lead
= nullptr;
128 for (int i
= 0; last_thread
&& i
< sys
->numContexts(); i
++) {
130 if (!(walk
= sys
->threadContexts
[i
]->getProcessPtr()))
134 * Threads in a thread group require special handing. For instance,
135 * we send the SIGCHLD signal so that it appears that it came from
136 * the head of the group. We also only delete file descriptors if
137 * we are the last thread in the thread group.
139 if (walk
->pid() == p
->tgid())
142 if ((sys
->threadContexts
[i
]->status() != ThreadContext::Halted
) &&
143 (sys
->threadContexts
[i
]->status() != ThreadContext::Halting
) &&
146 * Check if we share thread group with the pointer; this denotes
147 * that we are not the last thread active in the thread group.
148 * Note that setting this to false also prevents further
149 * iterations of the loop.
151 if (walk
->tgid() == p
->tgid()) {
153 * If p is trying to exit_group and both walk and p are in
154 * the same thread group (i.e., sharing the same tgid),
155 * we need to halt walk's thread context. After all threads
156 * except p are halted, p becomes the last thread in the
159 * If p is not doing exit_group and there exists another
160 * active thread context in the group, last_thread is
161 * set to false to prevent the parent thread from killing
162 * all threads in the group.
164 if (*(p
->exitGroup
)) {
165 sys
->threadContexts
[i
]->halt();
172 * A corner case exists which involves execve(). After execve(),
173 * the execve will enable SIGCHLD in the process. The problem
174 * occurs when the exiting process is the root process in the
175 * system; there is no parent to receive the signal. We obviate
176 * this problem by setting the root process' ppid to zero in the
177 * Python configuration files. We really should handle the
178 * root/execve specific case more gracefully.
180 if (*p
->sigchld
&& (p
->ppid() != 0) && (walk
->pid() == p
->ppid()))
188 sys
->signalList
.push_back(BasicSignal(tg_lead
, parent
, SIGCHLD
));
192 * Run though FD array of the exiting process and close all file
193 * descriptors except for the standard file descriptors.
194 * (The standard file descriptors are shared with gem5.)
196 for (int i
= 0; i
< p
->fds
->getSize(); i
++) {
198 p
->fds
->closeFDEntry(i
);
205 * check to see if there is no more active thread in the system. If so,
206 * exit the simulation loop
208 int activeContexts
= 0;
209 for (auto &system
: sys
->systemList
)
210 activeContexts
+= system
->numRunningContexts();
212 if (activeContexts
== 0) {
214 * Even though we are terminating the final thread context, dist-gem5
215 * requires the simulation to remain active and provide
216 * synchronization messages to the switch process. So we just halt
217 * the last thread context and return. The simulation will be
218 * terminated by dist-gem5 in a coordinated manner once all nodes
219 * have signaled their readiness to exit. For non dist-gem5
220 * simulations, readyToExit() always returns true.
222 if (!DistIface::readyToExit(0)) {
226 exitSimLoop("exiting with last active thread context", status
& 0xff);
234 exitFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
, int status
)
236 return exitImpl(desc
, callnum
, tc
, false, status
);
240 exitGroupFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
, int status
)
242 return exitImpl(desc
, callnum
, tc
, true, status
);
246 getpagesizeFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
)
248 return (int)PageBytes
;
253 brkFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
256 // change brk addr to first arg
257 auto p
= tc
->getProcessPtr();
259 std::shared_ptr
<MemState
> mem_state
= p
->memState
;
260 Addr brk_point
= mem_state
->getBrkPoint();
262 // in Linux at least, brk(0) returns the current break value
263 // (note that the syscall and the glibc function have different behavior)
267 if (new_brk
> brk_point
) {
268 // might need to allocate some new pages
269 for (ChunkGenerator
gen(brk_point
,
271 PageBytes
); !gen
.done(); gen
.next()) {
272 if (!p
->pTable
->translate(gen
.addr()))
273 p
->allocateMem(roundDown(gen
.addr(), PageBytes
), PageBytes
);
275 // if the address is already there, zero it out
278 PortProxy
&tp
= tc
->getVirtProxy();
280 // split non-page aligned accesses
281 Addr next_page
= roundUp(gen
.addr(), PageBytes
);
282 uint32_t size_needed
= next_page
- gen
.addr();
283 tp
.memsetBlob(gen
.addr(), zero
, size_needed
);
284 if (gen
.addr() + PageBytes
> next_page
&&
285 next_page
< new_brk
&&
286 p
->pTable
->translate(next_page
)) {
287 size_needed
= PageBytes
- size_needed
;
288 tp
.memsetBlob(next_page
, zero
, size_needed
);
294 mem_state
->setBrkPoint(new_brk
);
295 DPRINTF_SYSCALL(Verbose
, "brk: break point changed to: %#X\n",
296 mem_state
->getBrkPoint());
297 return mem_state
->getBrkPoint();
301 setTidAddressFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
,
304 auto process
= tc
->getProcessPtr();
306 process
->childClearTID
= tidPtr
;
307 return process
->pid();
311 closeFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
, int tgt_fd
)
313 auto p
= tc
->getProcessPtr();
314 return p
->fds
->closeFDEntry(tgt_fd
);
318 lseekFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
319 int tgt_fd
, uint64_t offs
, int whence
)
321 auto p
= tc
->getProcessPtr();
323 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
326 int sim_fd
= ffdp
->getSimFD();
328 off_t result
= lseek(sim_fd
, offs
, whence
);
330 return (result
== (off_t
)-1) ? -errno
: result
;
335 _llseekFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
336 int tgt_fd
, uint64_t offset_high
, uint32_t offset_low
,
337 Addr result_ptr
, int whence
)
339 auto p
= tc
->getProcessPtr();
341 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
344 int sim_fd
= ffdp
->getSimFD();
346 uint64_t offset
= (offset_high
<< 32) | offset_low
;
348 uint64_t result
= lseek(sim_fd
, offset
, whence
);
349 result
= htog(result
, tc
->getSystemPtr()->getGuestByteOrder());
351 if (result
== (off_t
)-1)
353 // Assuming that the size of loff_t is 64 bits on the target platform
354 BufferArg
result_buf(result_ptr
, sizeof(result
));
355 memcpy(result_buf
.bufferPtr(), &result
, sizeof(result
));
356 result_buf
.copyOut(tc
->getVirtProxy());
362 munmapFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
)
364 // With mmap more fully implemented, it might be worthwhile to bite
365 // the bullet and implement munmap. Should allow us to reuse simulated
371 const char *hostname
= "m5.eecs.umich.edu";
374 gethostnameFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
375 Addr buf_ptr
, int name_len
)
377 BufferArg
name(buf_ptr
, name_len
);
378 strncpy((char *)name
.bufferPtr(), hostname
, name_len
);
379 name
.copyOut(tc
->getVirtProxy());
384 getcwdFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
385 Addr buf_ptr
, unsigned long size
)
388 auto p
= tc
->getProcessPtr();
389 BufferArg
buf(buf_ptr
, size
);
391 // Is current working directory defined?
392 string cwd
= p
->tgtCwd
;
394 if (cwd
.length() >= size
) {
398 strncpy((char *)buf
.bufferPtr(), cwd
.c_str(), size
);
399 result
= cwd
.length();
401 if (getcwd((char *)buf
.bufferPtr(), size
)) {
402 result
= strlen((char *)buf
.bufferPtr());
408 buf
.copyOut(tc
->getVirtProxy());
410 return (result
== -1) ? -errno
: result
;
414 readlinkFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
415 Addr pathname
, Addr buf_ptr
, size_t bufsiz
)
418 auto p
= tc
->getProcessPtr();
420 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
423 // Adjust path for cwd and redirection
424 path
= p
->checkPathRedirect(path
);
426 BufferArg
buf(buf_ptr
, bufsiz
);
429 if (path
!= "/proc/self/exe") {
430 result
= readlink(path
.c_str(), (char *)buf
.bufferPtr(), bufsiz
);
432 // Emulate readlink() called on '/proc/self/exe' should return the
433 // absolute path of the binary running in the simulated system (the
434 // Process' executable). It is possible that using this path in
435 // the simulated system will result in unexpected behavior if:
436 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
437 // called binary calls readlink().
438 // 2) The host's full path to the running benchmark changes from one
439 // simulation to another. This can result in different simulated
440 // performance since the simulated system will process the binary
441 // path differently, even if the binary itself does not change.
443 // Get the absolute canonical path to the running application
444 char real_path
[PATH_MAX
];
445 char *check_real_path
= realpath(p
->progName(), real_path
);
446 if (!check_real_path
) {
447 fatal("readlink('/proc/self/exe') unable to resolve path to "
448 "executable: %s", p
->progName());
450 strncpy((char*)buf
.bufferPtr(), real_path
, bufsiz
);
451 size_t real_path_len
= strlen(real_path
);
452 if (real_path_len
> bufsiz
) {
453 // readlink will truncate the contents of the
454 // path to ensure it is no more than bufsiz
457 result
= real_path_len
;
460 // Issue a warning about potential unexpected results
461 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
462 "results in various settings.\n Returning '%s'\n",
463 (char*)buf
.bufferPtr());
466 buf
.copyOut(tc
->getVirtProxy());
468 return (result
== -1) ? -errno
: result
;
472 unlinkFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
, Addr pathname
)
475 auto p
= tc
->getProcessPtr();
477 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
480 path
= p
->checkPathRedirect(path
);
482 int result
= unlink(path
.c_str());
483 return (result
== -1) ? -errno
: result
;
487 linkFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
488 Addr pathname
, Addr new_pathname
)
492 auto p
= tc
->getProcessPtr();
494 auto &virt_mem
= tc
->getVirtProxy();
495 if (!virt_mem
.tryReadString(path
, pathname
))
497 if (!virt_mem
.tryReadString(new_path
, new_pathname
))
500 path
= p
->absolutePath(path
, true);
501 new_path
= p
->absolutePath(new_path
, true);
503 int result
= link(path
.c_str(), new_path
.c_str());
504 return (result
== -1) ? -errno
: result
;
508 symlinkFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
509 Addr pathname
, Addr new_pathname
)
513 auto p
= tc
->getProcessPtr();
515 auto &virt_mem
= tc
->getVirtProxy();
516 if (!virt_mem
.tryReadString(path
, pathname
))
518 if (!virt_mem
.tryReadString(new_path
, new_pathname
))
521 path
= p
->absolutePath(path
, true);
522 new_path
= p
->absolutePath(new_path
, true);
524 int result
= symlink(path
.c_str(), new_path
.c_str());
525 return (result
== -1) ? -errno
: result
;
529 mkdirFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
530 Addr pathname
, mode_t mode
)
532 auto p
= tc
->getProcessPtr();
534 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
537 path
= p
->checkPathRedirect(path
);
539 auto result
= mkdir(path
.c_str(), mode
);
540 return (result
== -1) ? -errno
: result
;
544 renameFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
545 Addr oldpath
, Addr newpath
)
547 auto p
= tc
->getProcessPtr();
550 if (!tc
->getVirtProxy().tryReadString(old_name
, oldpath
))
554 if (!tc
->getVirtProxy().tryReadString(new_name
, newpath
))
557 // Adjust path for cwd and redirection
558 old_name
= p
->checkPathRedirect(old_name
);
559 new_name
= p
->checkPathRedirect(new_name
);
561 int64_t result
= rename(old_name
.c_str(), new_name
.c_str());
562 return (result
== -1) ? -errno
: result
;
566 truncateFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
567 Addr pathname
, off_t length
)
570 auto p
= tc
->getProcessPtr();
572 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
575 // Adjust path for cwd and redirection
576 path
= p
->checkPathRedirect(path
);
578 int result
= truncate(path
.c_str(), length
);
579 return (result
== -1) ? -errno
: result
;
583 ftruncateFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
584 int tgt_fd
, off_t length
)
586 auto p
= tc
->getProcessPtr();
588 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
591 int sim_fd
= ffdp
->getSimFD();
593 int result
= ftruncate(sim_fd
, length
);
594 return (result
== -1) ? -errno
: result
;
598 truncate64Func(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
599 Addr pathname
, int64_t length
)
601 auto process
= tc
->getProcessPtr();
604 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
607 // Adjust path for cwd and redirection
608 path
= process
->checkPathRedirect(path
);
611 int result
= truncate(path
.c_str(), length
);
613 int result
= truncate64(path
.c_str(), length
);
615 return (result
== -1) ? -errno
: result
;
619 ftruncate64Func(SyscallDesc
*desc
, int num
, ThreadContext
*tc
)
622 auto p
= tc
->getProcessPtr();
623 int tgt_fd
= p
->getSyscallArg(tc
, index
);
624 int64_t length
= p
->getSyscallArg(tc
, index
, 64);
626 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
629 int sim_fd
= ffdp
->getSimFD();
632 int result
= ftruncate(sim_fd
, length
);
634 int result
= ftruncate64(sim_fd
, length
);
636 return (result
== -1) ? -errno
: result
;
640 umaskFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
)
642 // Letting the simulated program change the simulator's umask seems like
643 // a bad idea. Compromise by just returning the current umask but not
644 // changing anything.
645 mode_t oldMask
= umask(0);
651 chownFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
652 Addr pathname
, uint32_t owner
, uint32_t group
)
655 auto p
= tc
->getProcessPtr();
657 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
661 uid_t hostOwner
= owner
;
662 gid_t hostGroup
= group
;
664 // Adjust path for cwd and redirection
665 path
= p
->checkPathRedirect(path
);
667 int result
= chown(path
.c_str(), hostOwner
, hostGroup
);
668 return (result
== -1) ? -errno
: result
;
672 fchownFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
673 int tgt_fd
, uint32_t owner
, uint32_t group
)
675 auto p
= tc
->getProcessPtr();
677 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
680 int sim_fd
= ffdp
->getSimFD();
683 uid_t hostOwner
= owner
;
684 gid_t hostGroup
= group
;
686 int result
= fchown(sim_fd
, hostOwner
, hostGroup
);
687 return (result
== -1) ? -errno
: result
;
691 * FIXME: The file description is not shared among file descriptors created
692 * with dup. Really, it's difficult to maintain fields like file offset or
693 * flags since an update to such a field won't be reflected in the metadata
694 * for the fd entries that we maintain for checkpoint restoration.
697 dupFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
, int tgt_fd
)
699 auto p
= tc
->getProcessPtr();
701 auto old_hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
704 int sim_fd
= old_hbfdp
->getSimFD();
706 int result
= dup(sim_fd
);
710 auto new_hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>(old_hbfdp
->clone());
711 new_hbfdp
->setSimFD(result
);
712 new_hbfdp
->setCOE(false);
713 return p
->fds
->allocFD(new_hbfdp
);
717 dup2Func(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
718 int old_tgt_fd
, int new_tgt_fd
)
720 auto p
= tc
->getProcessPtr();
721 auto old_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[old_tgt_fd
]);
724 int old_sim_fd
= old_hbp
->getSimFD();
727 * We need a valid host file descriptor number to be able to pass into
728 * the second parameter for dup2 (newfd), but we don't know what the
729 * viable numbers are; we execute the open call to retrieve one.
731 int res_fd
= dup2(old_sim_fd
, open("/dev/null", O_RDONLY
));
735 auto new_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[new_tgt_fd
]);
737 p
->fds
->closeFDEntry(new_tgt_fd
);
738 new_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>(old_hbp
->clone());
739 new_hbp
->setSimFD(res_fd
);
740 new_hbp
->setCOE(false);
742 return p
->fds
->allocFD(new_hbp
);
746 fcntlFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
)
750 auto p
= tc
->getProcessPtr();
751 int tgt_fd
= p
->getSyscallArg(tc
, index
);
752 int cmd
= p
->getSyscallArg(tc
, index
);
754 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
757 int sim_fd
= hbfdp
->getSimFD();
759 int coe
= hbfdp
->getCOE();
763 return coe
& FD_CLOEXEC
;
766 arg
= p
->getSyscallArg(tc
, index
);
767 arg
? hbfdp
->setCOE(true) : hbfdp
->setCOE(false);
771 // Rely on the host to maintain the file status flags for this file
772 // description rather than maintain it ourselves. Admittedly, this
773 // is suboptimal (and possibly error prone), but it is difficult to
774 // maintain the flags by tracking them across the different descriptors
775 // (that refer to this file description) caused by clone, dup, and
776 // subsequent fcntls.
779 arg
= p
->getSyscallArg(tc
, index
);
780 int rv
= fcntl(sim_fd
, cmd
, arg
);
781 return (rv
== -1) ? -errno
: rv
;
785 warn("fcntl: unsupported command %d\n", cmd
);
791 fcntl64Func(SyscallDesc
*desc
, int num
, ThreadContext
*tc
)
794 auto p
= tc
->getProcessPtr();
795 int tgt_fd
= p
->getSyscallArg(tc
, index
);
797 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
800 int sim_fd
= hbfdp
->getSimFD();
802 int cmd
= p
->getSyscallArg(tc
, index
);
805 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd
);
808 case 34: // F_SETLK64
809 case 35: // F_SETLKW64
810 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
815 // not sure if this is totally valid, but we'll pass it through
816 // to the underlying OS
817 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd
, cmd
);
818 return fcntl(sim_fd
, cmd
);
823 pipeImpl(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
, bool pseudo_pipe
,
828 auto p
= tc
->getProcessPtr();
831 tgt_addr
= p
->getSyscallArg(tc
, index
);
833 flags
= p
->getSyscallArg(tc
, index
);
837 int sim_fds
[2], tgt_fds
[2];
839 int pipe_retval
= pipe(sim_fds
);
840 if (pipe_retval
== -1)
843 auto rend
= PipeFDEntry::EndType::read
;
844 auto rpfd
= std::make_shared
<PipeFDEntry
>(sim_fds
[0], O_WRONLY
, rend
);
845 tgt_fds
[0] = p
->fds
->allocFD(rpfd
);
846 int sim_fd_rpfd
= rpfd
->getSimFD();
848 auto wend
= PipeFDEntry::EndType::write
;
849 auto wpfd
= std::make_shared
<PipeFDEntry
>(sim_fds
[1], O_RDONLY
, wend
);
850 tgt_fds
[1] = p
->fds
->allocFD(wpfd
);
851 int sim_fd_wpfd
= wpfd
->getSimFD();
854 * Now patch the read object to record the target file descriptor chosen
855 * as the write end of the pipe.
857 rpfd
->setPipeReadSource(tgt_fds
[1]);
860 * Alpha Linux convention for pipe() is that fd[0] is returned as
861 * the return value of the function, and fd[1] is returned in r20.
864 tc
->setIntReg(SyscallPseudoReturnReg
, tgt_fds
[1]);
869 * Copy the target file descriptors into buffer space and then copy
870 * the buffer space back into the target address space.
872 BufferArg
tgt_handle(tgt_addr
, sizeof(int[2]));
873 int *buf_ptr
= (int*)tgt_handle
.bufferPtr();
874 buf_ptr
[0] = tgt_fds
[0];
875 buf_ptr
[1] = tgt_fds
[1];
876 tgt_handle
.copyOut(tc
->getVirtProxy());
878 // pipe2 has additional behavior if flags != 0
879 if (is_pipe2
&& flags
) {
880 // pipe2 only uses O_NONBLOCK, O_CLOEXEC, and (O_NONBLOCK | O_CLOEXEC)
881 // if flags set to anything else, return EINVAL
882 if ((flags
!= O_CLOEXEC
) && (flags
!= O_NONBLOCK
) &&
883 (flags
!= (O_CLOEXEC
| O_NONBLOCK
))) {
888 If O_NONBLOCK is passed in as a flag to pipe2, set O_NONBLOCK file
889 status flag for two new open file descriptors.
891 if (flags
& O_NONBLOCK
) {
893 O_NONBLOCK is set when the programmer wants to avoid a separate
894 call(s) to fcntl in their code, so mirror the fcntl
895 implementation for handling file descriptors -- rely on host to
896 maintain file status flags.
898 if (fcntl(sim_fd_rpfd
, F_SETFL
, O_NONBLOCK
)) {
901 if (fcntl(sim_fd_wpfd
, F_SETFL
, O_NONBLOCK
)) {
907 If O_CLOEXEC is passed in as a flag to pipe2, set close-on-exec
908 (FD_CLOEXEC) file status flag for two new open file descriptors.
910 if (flags
& O_CLOEXEC
) {
920 pipePseudoFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
922 return pipeImpl(desc
, callnum
, tc
, true);
926 pipeFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
928 return pipeImpl(desc
, callnum
, tc
, false);
932 pipe2Func(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
934 // call pipeImpl since the only difference between pipe and pipe2 is
935 // the flags values and what they do (at the end of pipeImpl)
936 return pipeImpl(desc
, callnum
, tc
, false, true);
940 getpgrpFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
942 auto process
= tc
->getProcessPtr();
943 return process
->pgid();
947 setpgidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
,
950 auto process
= tc
->getProcessPtr();
956 process
->pgid(process
->pid());
960 Process
*matched_ph
= nullptr;
961 System
*sysh
= tc
->getSystemPtr();
963 // Retrieves process pointer from active/suspended thread contexts.
964 for (int i
= 0; i
< sysh
->numContexts(); i
++) {
965 if (sysh
->threadContexts
[i
]->status() != ThreadContext::Halted
) {
966 Process
*temp_h
= sysh
->threadContexts
[i
]->getProcessPtr();
967 Process
*walk_ph
= (Process
*)temp_h
;
969 if (walk_ph
&& walk_ph
->pid() == process
->pid())
970 matched_ph
= walk_ph
;
975 matched_ph
->pgid((pgid
== 0) ? matched_ph
->pid() : pgid
);
981 getpidPseudoFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
983 // Make up a PID. There's no interprocess communication in
984 // fake_syscall mode, so there's no way for a process to know it's
985 // not getting a unique value.
987 auto process
= tc
->getProcessPtr();
988 tc
->setIntReg(SyscallPseudoReturnReg
, process
->ppid());
989 return process
->pid();
994 getuidPseudoFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
996 // Make up a UID and EUID... it shouldn't matter, and we want the
997 // simulation to be deterministic.
1000 auto process
= tc
->getProcessPtr();
1001 tc
->setIntReg(SyscallPseudoReturnReg
, process
->euid()); // EUID
1002 return process
->uid(); // UID
1007 getgidPseudoFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1009 // Get current group ID. EGID goes in r20.
1010 auto process
= tc
->getProcessPtr();
1011 tc
->setIntReg(SyscallPseudoReturnReg
, process
->egid()); // EGID
1012 return process
->gid();
1017 setuidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
, int uid
)
1019 // can't fathom why a benchmark would call this.
1020 warn("Ignoring call to setuid(%d)\n", uid
);
1025 getpidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1027 auto process
= tc
->getProcessPtr();
1028 return process
->tgid();
1032 gettidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1034 auto process
= tc
->getProcessPtr();
1035 return process
->pid();
1039 getppidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1041 auto process
= tc
->getProcessPtr();
1042 return process
->ppid();
1046 getuidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1048 auto process
= tc
->getProcessPtr();
1049 return process
->uid(); // UID
1053 geteuidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1055 auto process
= tc
->getProcessPtr();
1056 return process
->euid(); // UID
1060 getgidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1062 auto process
= tc
->getProcessPtr();
1063 return process
->gid();
1067 getegidFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
)
1069 auto process
= tc
->getProcessPtr();
1070 return process
->egid();
1074 fallocateFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
,
1075 int tgt_fd
, int mode
, off_t offset
, off_t len
)
1077 #if defined(__linux__)
1078 auto p
= tc
->getProcessPtr();
1080 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
1083 int sim_fd
= ffdp
->getSimFD();
1085 int result
= fallocate(sim_fd
, mode
, offset
, len
);
1090 warnUnsupportedOS("fallocate");
1096 accessFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
,
1097 Addr pathname
, mode_t mode
)
1100 auto p
= tc
->getProcessPtr();
1101 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1104 // Adjust path for cwd and redirection
1105 path
= p
->checkPathRedirect(path
);
1107 int result
= access(path
.c_str(), mode
);
1108 return (result
== -1) ? -errno
: result
;
1112 mknodFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1113 Addr pathname
, mode_t mode
, dev_t dev
)
1115 auto p
= tc
->getProcessPtr();
1117 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1120 path
= p
->checkPathRedirect(path
);
1122 auto result
= mknod(path
.c_str(), mode
, dev
);
1123 return (result
== -1) ? -errno
: result
;
1127 chdirFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
, Addr pathname
)
1129 auto p
= tc
->getProcessPtr();
1131 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1134 std::string tgt_cwd
;
1135 if (startswith(path
, "/")) {
1139 tgt_cwd
= realpath((p
->tgtCwd
+ "/" + path
).c_str(), buf
);
1141 std::string host_cwd
= p
->checkPathRedirect(tgt_cwd
);
1143 int result
= chdir(host_cwd
.c_str());
1148 p
->hostCwd
= host_cwd
;
1149 p
->tgtCwd
= tgt_cwd
;
1154 rmdirFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
, Addr pathname
)
1156 auto p
= tc
->getProcessPtr();
1158 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1161 path
= p
->checkPathRedirect(path
);
1163 auto result
= rmdir(path
.c_str());
1164 return (result
== -1) ? -errno
: result
;
1167 #if defined(SYS_getdents) || defined(SYS_getdents64)
1168 template<typename DE
, int SYS_NUM
>
1169 static SyscallReturn
1170 getdentsImpl(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
,
1171 int tgt_fd
, Addr buf_ptr
, unsigned count
)
1173 auto p
= tc
->getProcessPtr();
1175 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
1178 int sim_fd
= hbfdp
->getSimFD();
1180 BufferArg
buf_arg(buf_ptr
, count
);
1181 auto status
= syscall(SYS_NUM
, sim_fd
, buf_arg
.bufferPtr(), count
);
1186 unsigned traversed
= 0;
1187 while (traversed
< status
) {
1188 DE
*buffer
= (DE
*)((Addr
)buf_arg
.bufferPtr() + traversed
);
1190 auto host_reclen
= buffer
->d_reclen
;
1193 * Convert the byte ordering from the host to the target before
1194 * passing the data back into the target's address space to preserve
1197 const ByteOrder bo
= tc
->getSystemPtr()->getGuestByteOrder();
1198 buffer
->d_ino
= htog(buffer
->d_ino
, bo
);
1199 buffer
->d_off
= htog(buffer
->d_off
, bo
);
1200 buffer
->d_reclen
= htog(buffer
->d_reclen
, bo
);
1202 traversed
+= host_reclen
;
1205 buf_arg
.copyOut(tc
->getVirtProxy());
1210 #if defined(SYS_getdents)
1212 getdentsFunc(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
,
1213 int tgt_fd
, Addr buf_ptr
, unsigned count
)
1215 typedef struct linux_dirent
{
1216 unsigned long d_ino
;
1217 unsigned long d_off
;
1218 unsigned short d_reclen
;
1222 return getdentsImpl
<LinDent
, SYS_getdents
>(desc
, callnum
, tc
,
1223 tgt_fd
, buf_ptr
, count
);
1227 #if defined(SYS_getdents64)
1229 getdents64Func(SyscallDesc
*desc
, int callnum
, ThreadContext
*tc
,
1230 int tgt_fd
, Addr buf_ptr
, unsigned count
)
1232 typedef struct linux_dirent64
{
1235 unsigned short d_reclen
;
1239 return getdentsImpl
<LinDent64
, SYS_getdents64
>(desc
, callnum
, tc
,
1240 tgt_fd
, buf_ptr
, count
);
1245 shutdownFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1246 int tgt_fd
, int how
)
1248 auto p
= tc
->getProcessPtr();
1250 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1253 int sim_fd
= sfdp
->getSimFD();
1255 int retval
= shutdown(sim_fd
, how
);
1257 return (retval
== -1) ? -errno
: retval
;
1261 bindFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1262 int tgt_fd
, Addr buf_ptr
, int addrlen
)
1264 auto p
= tc
->getProcessPtr();
1266 BufferArg
bufSock(buf_ptr
, addrlen
);
1267 bufSock
.copyIn(tc
->getVirtProxy());
1269 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1272 int sim_fd
= sfdp
->getSimFD();
1274 int status
= ::bind(sim_fd
,
1275 (struct sockaddr
*)bufSock
.bufferPtr(),
1278 return (status
== -1) ? -errno
: status
;
1282 listenFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1283 int tgt_fd
, int backlog
)
1285 auto p
= tc
->getProcessPtr();
1287 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1290 int sim_fd
= sfdp
->getSimFD();
1292 int status
= listen(sim_fd
, backlog
);
1294 return (status
== -1) ? -errno
: status
;
1298 connectFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1299 int tgt_fd
, Addr buf_ptr
, int addrlen
)
1301 auto p
= tc
->getProcessPtr();
1303 BufferArg
addr(buf_ptr
, addrlen
);
1304 addr
.copyIn(tc
->getVirtProxy());
1306 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1309 int sim_fd
= sfdp
->getSimFD();
1311 int status
= connect(sim_fd
,
1312 (struct sockaddr
*)addr
.bufferPtr(),
1313 (socklen_t
)addrlen
);
1315 return (status
== -1) ? -errno
: status
;
1319 recvfromFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1320 int tgt_fd
, Addr bufrPtr
, size_t bufrLen
, int flags
,
1321 Addr addrPtr
, Addr addrlenPtr
)
1323 auto p
= tc
->getProcessPtr();
1325 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1328 int sim_fd
= sfdp
->getSimFD();
1330 // Reserve buffer space.
1331 BufferArg
bufrBuf(bufrPtr
, bufrLen
);
1333 // Get address length.
1334 socklen_t addrLen
= 0;
1335 if (addrlenPtr
!= 0) {
1336 // Read address length parameter.
1337 BufferArg
addrlenBuf(addrlenPtr
, sizeof(socklen_t
));
1338 addrlenBuf
.copyIn(tc
->getVirtProxy());
1339 addrLen
= *((socklen_t
*)addrlenBuf
.bufferPtr());
1342 struct sockaddr sa
, *sap
= NULL
;
1344 BufferArg
addrBuf(addrPtr
, addrLen
);
1345 addrBuf
.copyIn(tc
->getVirtProxy());
1346 memcpy(&sa
, (struct sockaddr
*)addrBuf
.bufferPtr(),
1347 sizeof(struct sockaddr
));
1351 ssize_t recvd_size
= recvfrom(sim_fd
,
1352 (void *)bufrBuf
.bufferPtr(),
1353 bufrLen
, flags
, sap
, (socklen_t
*)&addrLen
);
1355 if (recvd_size
== -1)
1358 // Pass the received data out.
1359 bufrBuf
.copyOut(tc
->getVirtProxy());
1361 // Copy address to addrPtr and pass it on.
1363 BufferArg
addrBuf(addrPtr
, addrLen
);
1364 memcpy(addrBuf
.bufferPtr(), sap
, sizeof(sa
));
1365 addrBuf
.copyOut(tc
->getVirtProxy());
1368 // Copy len to addrlenPtr and pass it on.
1370 BufferArg
addrlenBuf(addrlenPtr
, sizeof(socklen_t
));
1371 *(socklen_t
*)addrlenBuf
.bufferPtr() = addrLen
;
1372 addrlenBuf
.copyOut(tc
->getVirtProxy());
1379 sendtoFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1380 int tgt_fd
, Addr bufrPtr
, size_t bufrLen
, int flags
,
1381 Addr addrPtr
, socklen_t addrLen
)
1383 auto p
= tc
->getProcessPtr();
1385 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1388 int sim_fd
= sfdp
->getSimFD();
1390 // Reserve buffer space.
1391 BufferArg
bufrBuf(bufrPtr
, bufrLen
);
1392 bufrBuf
.copyIn(tc
->getVirtProxy());
1394 struct sockaddr sa
, *sap
= nullptr;
1395 memset(&sa
, 0, sizeof(sockaddr
));
1397 BufferArg
addrBuf(addrPtr
, addrLen
);
1398 addrBuf
.copyIn(tc
->getVirtProxy());
1399 memcpy(&sa
, (sockaddr
*)addrBuf
.bufferPtr(), addrLen
);
1403 ssize_t sent_size
= sendto(sim_fd
,
1404 (void *)bufrBuf
.bufferPtr(),
1405 bufrLen
, flags
, sap
, (socklen_t
)addrLen
);
1407 return (sent_size
== -1) ? -errno
: sent_size
;
1411 recvmsgFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1412 int tgt_fd
, Addr msgPtr
, int flags
)
1414 auto p
= tc
->getProcessPtr();
1416 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1419 int sim_fd
= sfdp
->getSimFD();
1423 * void *msg_name; // optional address
1424 * socklen_t msg_namelen; // size of address
1425 * struct iovec *msg_iov; // iovec array
1426 * size_t msg_iovlen; // number entries in msg_iov
1427 * i // entries correspond to buffer
1428 * void *msg_control; // ancillary data
1429 * size_t msg_controllen; // ancillary data buffer len
1430 * int msg_flags; // flags on received message
1434 * void *iov_base; // starting address
1435 * size_t iov_len; // number of bytes to transfer
1440 * The plan with this system call is to replace all of the pointers in the
1441 * structure and the substructure with BufferArg class pointers. We will
1442 * copy every field from the structures into our BufferArg classes.
1444 BufferArg
msgBuf(msgPtr
, sizeof(struct msghdr
));
1445 msgBuf
.copyIn(tc
->getVirtProxy());
1446 struct msghdr
*msgHdr
= (struct msghdr
*)msgBuf
.bufferPtr();
1449 * We will use these address place holders to retain the pointers which
1450 * we are going to replace with our own buffers in our simulator address
1453 Addr msg_name_phold
= 0;
1454 Addr msg_iov_phold
= 0;
1455 Addr iovec_base_phold
[msgHdr
->msg_iovlen
];
1456 Addr msg_control_phold
= 0;
1459 * Record msg_name pointer then replace with buffer pointer.
1461 BufferArg
*nameBuf
= NULL
;
1462 if (msgHdr
->msg_name
) {
1463 /*1*/msg_name_phold
= (Addr
)msgHdr
->msg_name
;
1464 /*2*/nameBuf
= new BufferArg(msg_name_phold
, msgHdr
->msg_namelen
);
1465 /*3*/nameBuf
->copyIn(tc
->getVirtProxy());
1466 /*4*/msgHdr
->msg_name
= nameBuf
->bufferPtr();
1470 * Record msg_iov pointer then replace with buffer pointer. Also, setup
1471 * an array of buffer pointers for the iovec structs record and replace
1472 * their pointers with buffer pointers.
1474 BufferArg
*iovBuf
= NULL
;
1475 BufferArg
*iovecBuf
[msgHdr
->msg_iovlen
];
1476 for (int i
= 0; i
< msgHdr
->msg_iovlen
; i
++) {
1477 iovec_base_phold
[i
] = 0;
1481 if (msgHdr
->msg_iov
) {
1482 /*1*/msg_iov_phold
= (Addr
)msgHdr
->msg_iov
;
1483 /*2*/iovBuf
= new BufferArg(msg_iov_phold
, msgHdr
->msg_iovlen
*
1484 sizeof(struct iovec
));
1485 /*3*/iovBuf
->copyIn(tc
->getVirtProxy());
1486 for (int i
= 0; i
< msgHdr
->msg_iovlen
; i
++) {
1487 if (((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
) {
1488 /*1*/iovec_base_phold
[i
] =
1489 (Addr
)((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
;
1490 /*2*/iovecBuf
[i
] = new BufferArg(iovec_base_phold
[i
],
1491 ((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_len
);
1492 /*3*/iovecBuf
[i
]->copyIn(tc
->getVirtProxy());
1493 /*4*/((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
=
1494 iovecBuf
[i
]->bufferPtr();
1497 /*4*/msgHdr
->msg_iov
= (struct iovec
*)iovBuf
->bufferPtr();
1501 * Record msg_control pointer then replace with buffer pointer.
1503 BufferArg
*controlBuf
= NULL
;
1504 if (msgHdr
->msg_control
) {
1505 /*1*/msg_control_phold
= (Addr
)msgHdr
->msg_control
;
1506 /*2*/controlBuf
= new BufferArg(msg_control_phold
,
1507 CMSG_ALIGN(msgHdr
->msg_controllen
));
1508 /*3*/controlBuf
->copyIn(tc
->getVirtProxy());
1509 /*4*/msgHdr
->msg_control
= controlBuf
->bufferPtr();
1512 ssize_t recvd_size
= recvmsg(sim_fd
, msgHdr
, flags
);
1517 if (msgHdr
->msg_name
) {
1518 nameBuf
->copyOut(tc
->getVirtProxy());
1520 msgHdr
->msg_name
= (void *)msg_name_phold
;
1523 if (msgHdr
->msg_iov
) {
1524 for (int i
= 0; i
< msgHdr
->msg_iovlen
; i
++) {
1525 if (((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
) {
1526 iovecBuf
[i
]->copyOut(tc
->getVirtProxy());
1528 ((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
=
1529 (void *)iovec_base_phold
[i
];
1532 iovBuf
->copyOut(tc
->getVirtProxy());
1534 msgHdr
->msg_iov
= (struct iovec
*)msg_iov_phold
;
1537 if (msgHdr
->msg_control
) {
1538 controlBuf
->copyOut(tc
->getVirtProxy());
1540 msgHdr
->msg_control
= (void *)msg_control_phold
;
1543 msgBuf
.copyOut(tc
->getVirtProxy());
1549 sendmsgFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1550 int tgt_fd
, Addr msgPtr
, int flags
)
1552 auto p
= tc
->getProcessPtr();
1554 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1557 int sim_fd
= sfdp
->getSimFD();
1560 * Reserve buffer space.
1562 BufferArg
msgBuf(msgPtr
, sizeof(struct msghdr
));
1563 msgBuf
.copyIn(tc
->getVirtProxy());
1564 struct msghdr msgHdr
= *((struct msghdr
*)msgBuf
.bufferPtr());
1567 * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
1568 * recvmsg without a buffer.
1570 struct iovec
*iovPtr
= msgHdr
.msg_iov
;
1571 BufferArg
iovBuf((Addr
)iovPtr
, sizeof(struct iovec
) * msgHdr
.msg_iovlen
);
1572 iovBuf
.copyIn(tc
->getVirtProxy());
1573 struct iovec
*iov
= (struct iovec
*)iovBuf
.bufferPtr();
1574 msgHdr
.msg_iov
= iov
;
1577 * Cannot instantiate buffers till inside the loop.
1578 * Create array to hold buffer addresses, to be used during copyIn of
1581 BufferArg
**bufferArray
= (BufferArg
**)malloc(msgHdr
.msg_iovlen
1582 * sizeof(BufferArg
*));
1585 * Iterate through the iovec structures:
1586 * Get the base buffer addreses, reserve iov_len amount of space for each.
1587 * Put the buf address into the bufferArray for later retrieval.
1589 for (int iovIndex
= 0 ; iovIndex
< msgHdr
.msg_iovlen
; iovIndex
++) {
1590 Addr basePtr
= (Addr
) iov
[iovIndex
].iov_base
;
1591 bufferArray
[iovIndex
] = new BufferArg(basePtr
, iov
[iovIndex
].iov_len
);
1592 bufferArray
[iovIndex
]->copyIn(tc
->getVirtProxy());
1593 iov
[iovIndex
].iov_base
= bufferArray
[iovIndex
]->bufferPtr();
1596 ssize_t sent_size
= sendmsg(sim_fd
, &msgHdr
, flags
);
1597 int local_errno
= errno
;
1600 * Free dynamically allocated memory.
1602 for (int iovIndex
= 0 ; iovIndex
< msgHdr
.msg_iovlen
; iovIndex
++) {
1603 BufferArg
*baseBuf
= ( BufferArg
*)bufferArray
[iovIndex
];
1612 return (sent_size
< 0) ? -local_errno
: sent_size
;
1616 getsockoptFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1617 int tgt_fd
, int level
, int optname
, Addr valPtr
, Addr lenPtr
)
1619 // union of all possible return value types from getsockopt
1623 struct linger linger_val
;
1624 struct timeval timeval_val
;
1627 auto p
= tc
->getProcessPtr();
1629 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1632 int sim_fd
= sfdp
->getSimFD();
1634 socklen_t len
= sizeof(val
);
1635 int status
= getsockopt(sim_fd
, level
, optname
, &val
, &len
);
1640 // copy val to valPtr and pass it on
1641 BufferArg
valBuf(valPtr
, sizeof(val
));
1642 memcpy(valBuf
.bufferPtr(), &val
, sizeof(val
));
1643 valBuf
.copyOut(tc
->getVirtProxy());
1645 // copy len to lenPtr and pass it on
1646 BufferArg
lenBuf(lenPtr
, sizeof(len
));
1647 memcpy(lenBuf
.bufferPtr(), &len
, sizeof(len
));
1648 lenBuf
.copyOut(tc
->getVirtProxy());
1654 getsocknameFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1655 int tgt_fd
, Addr addrPtr
, Addr lenPtr
)
1657 auto p
= tc
->getProcessPtr();
1659 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1662 int sim_fd
= sfdp
->getSimFD();
1664 // lenPtr is an in-out paramenter:
1665 // sending the address length in, conveying the final length out
1667 // Read in the value of len from the passed pointer.
1668 BufferArg
lenBuf(lenPtr
, sizeof(socklen_t
));
1669 lenBuf
.copyIn(tc
->getVirtProxy());
1670 socklen_t len
= *(socklen_t
*)lenBuf
.bufferPtr();
1673 int status
= getsockname(sim_fd
, &sa
, &len
);
1678 // Copy address to addrPtr and pass it on.
1679 BufferArg
addrBuf(addrPtr
, sizeof(sa
));
1680 memcpy(addrBuf
.bufferPtr(), &sa
, sizeof(sa
));
1681 addrBuf
.copyOut(tc
->getVirtProxy());
1683 // Copy len to lenPtr and pass it on.
1684 *(socklen_t
*)lenBuf
.bufferPtr() = len
;
1685 lenBuf
.copyOut(tc
->getVirtProxy());
1691 getpeernameFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1692 int tgt_fd
, Addr sockAddrPtr
, Addr addrlenPtr
)
1694 auto p
= tc
->getProcessPtr();
1696 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1699 int sim_fd
= sfdp
->getSimFD();
1701 BufferArg
bufAddrlen(addrlenPtr
, sizeof(unsigned));
1702 bufAddrlen
.copyIn(tc
->getVirtProxy());
1703 BufferArg
bufSock(sockAddrPtr
, *(unsigned *)bufAddrlen
.bufferPtr());
1705 int retval
= getpeername(sim_fd
,
1706 (struct sockaddr
*)bufSock
.bufferPtr(),
1707 (unsigned *)bufAddrlen
.bufferPtr());
1710 bufSock
.copyOut(tc
->getVirtProxy());
1711 bufAddrlen
.copyOut(tc
->getVirtProxy());
1714 return (retval
== -1) ? -errno
: retval
;
1718 setsockoptFunc(SyscallDesc
*desc
, int num
, ThreadContext
*tc
,
1719 int tgt_fd
, int level
, int optname
, Addr valPtr
, socklen_t len
)
1721 auto p
= tc
->getProcessPtr();
1723 BufferArg
valBuf(valPtr
, len
);
1724 valBuf
.copyIn(tc
->getVirtProxy());
1726 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1729 int sim_fd
= sfdp
->getSimFD();
1731 int status
= setsockopt(sim_fd
, level
, optname
,
1732 (struct sockaddr
*)valBuf
.bufferPtr(), len
);
1734 return (status
== -1) ? -errno
: status
;