gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
syscall_emul.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003-2005 The Regents of The University of Michigan
3  * All rights reserved.
4  *
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.
15  *
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.
27  *
28  * Authors: Steve Reinhardt
29  * Ali Saidi
30  */
31 
32 #include "sim/syscall_emul.hh"
33 
34 #include <fcntl.h>
35 #include <sys/syscall.h>
36 #include <unistd.h>
37 
38 #include <csignal>
39 #include <iostream>
40 #include <mutex>
41 #include <string>
42 #include <unordered_map>
43 
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"
55 #include "sim/syscall_desc.hh"
56 #include "sim/system.hh"
57 
58 using namespace std;
59 using namespace TheISA;
60 
61 void
62 warnUnsupportedOS(std::string syscall_name)
63 {
64  warn("Cannot invoke %s on host operating system.", syscall_name);
65 }
66 
69 {
70  fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum);
71 
72  return 1;
73 }
74 
75 
77 ignoreFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
78 {
79  warn("ignoring syscall %s(...)", desc->name());
80  return 0;
81 }
82 
85 {
86  static std::unordered_map<SyscallDesc *, bool> bool_map;
87 
88  bool &warned = bool_map[desc];
89  if (!warned) {
90  warn("ignoring syscall %s(...)\n"
91  " (further warnings will be suppressed)", desc->name());
92  warned = true;
93  }
94 
95  return 0;
96 }
97 
98 static void
99 exitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid)
100 {
101  // Clear value at address pointed to by thread's childClearTID field.
102  BufferArg ctidBuf(addr, sizeof(long));
103  long *ctid = (long *)ctidBuf.bufferPtr();
104  *ctid = 0;
105  ctidBuf.copyOut(tc->getVirtProxy());
106 
107  FutexMap &futex_map = tc->getSystemPtr()->futexMap;
108  // Wake one of the waiting threads.
109  futex_map.wakeup(addr, tgid, 1);
110 }
111 
112 static SyscallReturn
113 exitImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool group,
114  int status)
115 {
116  auto p = tc->getProcessPtr();
117 
118  System *sys = tc->getSystemPtr();
119 
120  if (group)
121  *p->exitGroup = true;
122 
123  if (p->childClearTID)
124  exitFutexWake(tc, p->childClearTID, p->tgid());
125 
126  bool last_thread = true;
127  Process *parent = nullptr, *tg_lead = nullptr;
128  for (int i = 0; last_thread && i < sys->numContexts(); i++) {
129  Process *walk;
130  if (!(walk = sys->threadContexts[i]->getProcessPtr()))
131  continue;
132 
139  if (walk->pid() == p->tgid())
140  tg_lead = walk;
141 
142  if ((sys->threadContexts[i]->status() != ThreadContext::Halted) &&
143  (sys->threadContexts[i]->status() != ThreadContext::Halting) &&
144  (walk != p)) {
151  if (walk->tgid() == p->tgid()) {
164  if (*(p->exitGroup)) {
165  sys->threadContexts[i]->halt();
166  } else {
167  last_thread = false;
168  }
169  }
170 
180  if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid()))
181  parent = walk;
182  }
183  }
184 
185  if (last_thread) {
186  if (parent) {
187  assert(tg_lead);
188  sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD));
189  }
190 
196  for (int i = 0; i < p->fds->getSize(); i++) {
197  if ((*p->fds)[i])
198  p->fds->closeFDEntry(i);
199  }
200  }
201 
202  tc->halt();
203 
208  int activeContexts = 0;
209  for (auto &system: sys->systemList)
210  activeContexts += system->numRunningContexts();
211 
212  if (activeContexts == 0) {
222  if (!DistIface::readyToExit(0)) {
223  return status;
224  }
225 
226  exitSimLoop("exiting with last active thread context", status & 0xff);
227  return status;
228  }
229 
230  return status;
231 }
232 
234 exitFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int status)
235 {
236  return exitImpl(desc, callnum, tc, false, status);
237 }
238 
240 exitGroupFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int status)
241 {
242  return exitImpl(desc, callnum, tc, true, status);
243 }
244 
247 {
248  return (int)PageBytes;
249 }
250 
251 
253 brkFunc(SyscallDesc *desc, int num, ThreadContext *tc,
254  Addr new_brk)
255 {
256  // change brk addr to first arg
257  auto p = tc->getProcessPtr();
258 
259  std::shared_ptr<MemState> mem_state = p->memState;
260  Addr brk_point = mem_state->getBrkPoint();
261 
262  // in Linux at least, brk(0) returns the current break value
263  // (note that the syscall and the glibc function have different behavior)
264  if (new_brk == 0)
265  return brk_point;
266 
267  if (new_brk > brk_point) {
268  // might need to allocate some new pages
269  for (ChunkGenerator gen(brk_point,
270  new_brk - brk_point,
271  PageBytes); !gen.done(); gen.next()) {
272  if (!p->pTable->translate(gen.addr()))
273  p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
274 
275  // if the address is already there, zero it out
276  else {
277  uint8_t zero = 0;
278  PortProxy &tp = tc->getVirtProxy();
279 
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);
289  }
290  }
291  }
292  }
293 
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();
298 }
299 
302  uint64_t tidPtr)
303 {
304  auto process = tc->getProcessPtr();
305 
306  process->childClearTID = tidPtr;
307  return process->pid();
308 }
309 
311 closeFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd)
312 {
313  auto p = tc->getProcessPtr();
314  return p->fds->closeFDEntry(tgt_fd);
315 }
316 
318 lseekFunc(SyscallDesc *desc, int num, ThreadContext *tc,
319  int tgt_fd, uint64_t offs, int whence)
320 {
321  auto p = tc->getProcessPtr();
322 
323  auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
324  if (!ffdp)
325  return -EBADF;
326  int sim_fd = ffdp->getSimFD();
327 
328  off_t result = lseek(sim_fd, offs, whence);
329 
330  return (result == (off_t)-1) ? -errno : result;
331 }
332 
333 
336  int tgt_fd, uint64_t offset_high, uint32_t offset_low,
337  Addr result_ptr, int whence)
338 {
339  auto p = tc->getProcessPtr();
340 
341  auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
342  if (!ffdp)
343  return -EBADF;
344  int sim_fd = ffdp->getSimFD();
345 
346  uint64_t offset = (offset_high << 32) | offset_low;
347 
348  uint64_t result = lseek(sim_fd, offset, whence);
349  result = htog(result, tc->getSystemPtr()->getGuestByteOrder());
350 
351  if (result == (off_t)-1)
352  return -errno;
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());
357  return 0;
358 }
359 
360 
363 {
364  // With mmap more fully implemented, it might be worthwhile to bite
365  // the bullet and implement munmap. Should allow us to reuse simulated
366  // memory.
367  return 0;
368 }
369 
370 
371 const char *hostname = "m5.eecs.umich.edu";
372 
375  Addr buf_ptr, int name_len)
376 {
377  BufferArg name(buf_ptr, name_len);
378  strncpy((char *)name.bufferPtr(), hostname, name_len);
379  name.copyOut(tc->getVirtProxy());
380  return 0;
381 }
382 
385  Addr buf_ptr, unsigned long size)
386 {
387  int result = 0;
388  auto p = tc->getProcessPtr();
389  BufferArg buf(buf_ptr, size);
390 
391  // Is current working directory defined?
392  string cwd = p->tgtCwd;
393  if (!cwd.empty()) {
394  if (cwd.length() >= size) {
395  // Buffer too small
396  return -ERANGE;
397  }
398  strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
399  result = cwd.length();
400  } else {
401  if (getcwd((char *)buf.bufferPtr(), size)) {
402  result = strlen((char *)buf.bufferPtr());
403  } else {
404  result = -1;
405  }
406  }
407 
408  buf.copyOut(tc->getVirtProxy());
409 
410  return (result == -1) ? -errno : result;
411 }
412 
415  Addr pathname, Addr buf_ptr, size_t bufsiz)
416 {
417  string path;
418  auto p = tc->getProcessPtr();
419 
420  if (!tc->getVirtProxy().tryReadString(path, pathname))
421  return -EFAULT;
422 
423  // Adjust path for cwd and redirection
424  path = p->checkPathRedirect(path);
425 
426  BufferArg buf(buf_ptr, bufsiz);
427 
428  int result = -1;
429  if (path != "/proc/self/exe") {
430  result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
431  } else {
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.
442 
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());
449  }
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
455  result = bufsiz;
456  } else {
457  result = real_path_len;
458  }
459 
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());
464  }
465 
466  buf.copyOut(tc->getVirtProxy());
467 
468  return (result == -1) ? -errno : result;
469 }
470 
472 unlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname)
473 {
474  string path;
475  auto p = tc->getProcessPtr();
476 
477  if (!tc->getVirtProxy().tryReadString(path, pathname))
478  return -EFAULT;
479 
480  path = p->checkPathRedirect(path);
481 
482  int result = unlink(path.c_str());
483  return (result == -1) ? -errno : result;
484 }
485 
487 linkFunc(SyscallDesc *desc, int num, ThreadContext *tc,
488  Addr pathname, Addr new_pathname)
489 {
490  string path;
491  string new_path;
492  auto p = tc->getProcessPtr();
493 
494  auto &virt_mem = tc->getVirtProxy();
495  if (!virt_mem.tryReadString(path, pathname))
496  return -EFAULT;
497  if (!virt_mem.tryReadString(new_path, new_pathname))
498  return -EFAULT;
499 
500  path = p->absolutePath(path, true);
501  new_path = p->absolutePath(new_path, true);
502 
503  int result = link(path.c_str(), new_path.c_str());
504  return (result == -1) ? -errno : result;
505 }
506 
509  Addr pathname, Addr new_pathname)
510 {
511  string path;
512  string new_path;
513  auto p = tc->getProcessPtr();
514 
515  auto &virt_mem = tc->getVirtProxy();
516  if (!virt_mem.tryReadString(path, pathname))
517  return -EFAULT;
518  if (!virt_mem.tryReadString(new_path, new_pathname))
519  return -EFAULT;
520 
521  path = p->absolutePath(path, true);
522  new_path = p->absolutePath(new_path, true);
523 
524  int result = symlink(path.c_str(), new_path.c_str());
525  return (result == -1) ? -errno : result;
526 }
527 
529 mkdirFunc(SyscallDesc *desc, int num, ThreadContext *tc,
530  Addr pathname, mode_t mode)
531 {
532  auto p = tc->getProcessPtr();
533  std::string path;
534  if (!tc->getVirtProxy().tryReadString(path, pathname))
535  return -EFAULT;
536 
537  path = p->checkPathRedirect(path);
538 
539  auto result = mkdir(path.c_str(), mode);
540  return (result == -1) ? -errno : result;
541 }
542 
545  Addr oldpath, Addr newpath)
546 {
547  auto p = tc->getProcessPtr();
548 
549  string old_name;
550  if (!tc->getVirtProxy().tryReadString(old_name, oldpath))
551  return -EFAULT;
552 
553  string new_name;
554  if (!tc->getVirtProxy().tryReadString(new_name, newpath))
555  return -EFAULT;
556 
557  // Adjust path for cwd and redirection
558  old_name = p->checkPathRedirect(old_name);
559  new_name = p->checkPathRedirect(new_name);
560 
561  int64_t result = rename(old_name.c_str(), new_name.c_str());
562  return (result == -1) ? -errno : result;
563 }
564 
567  Addr pathname, off_t length)
568 {
569  string path;
570  auto p = tc->getProcessPtr();
571 
572  if (!tc->getVirtProxy().tryReadString(path, pathname))
573  return -EFAULT;
574 
575  // Adjust path for cwd and redirection
576  path = p->checkPathRedirect(path);
577 
578  int result = truncate(path.c_str(), length);
579  return (result == -1) ? -errno : result;
580 }
581 
584  int tgt_fd, off_t length)
585 {
586  auto p = tc->getProcessPtr();
587 
588  auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
589  if (!ffdp)
590  return -EBADF;
591  int sim_fd = ffdp->getSimFD();
592 
593  int result = ftruncate(sim_fd, length);
594  return (result == -1) ? -errno : result;
595 }
596 
599  Addr pathname, int64_t length)
600 {
601  auto process = tc->getProcessPtr();
602  string path;
603 
604  if (!tc->getVirtProxy().tryReadString(path, pathname))
605  return -EFAULT;
606 
607  // Adjust path for cwd and redirection
608  path = process->checkPathRedirect(path);
609 
610 #if NO_STAT64
611  int result = truncate(path.c_str(), length);
612 #else
613  int result = truncate64(path.c_str(), length);
614 #endif
615  return (result == -1) ? -errno : result;
616 }
617 
620 {
621  int index = 0;
622  auto p = tc->getProcessPtr();
623  int tgt_fd = p->getSyscallArg(tc, index);
624  int64_t length = p->getSyscallArg(tc, index, 64);
625 
626  auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
627  if (!ffdp)
628  return -EBADF;
629  int sim_fd = ffdp->getSimFD();
630 
631 #if NO_STAT64
632  int result = ftruncate(sim_fd, length);
633 #else
634  int result = ftruncate64(sim_fd, length);
635 #endif
636  return (result == -1) ? -errno : result;
637 }
638 
640 umaskFunc(SyscallDesc *desc, int num, ThreadContext *tc)
641 {
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);
646  umask(oldMask);
647  return (int)oldMask;
648 }
649 
651 chownFunc(SyscallDesc *desc, int num, ThreadContext *tc,
652  Addr pathname, uint32_t owner, uint32_t group)
653 {
654  string path;
655  auto p = tc->getProcessPtr();
656 
657  if (!tc->getVirtProxy().tryReadString(path, pathname))
658  return -EFAULT;
659 
660  /* XXX endianess */
661  uid_t hostOwner = owner;
662  gid_t hostGroup = group;
663 
664  // Adjust path for cwd and redirection
665  path = p->checkPathRedirect(path);
666 
667  int result = chown(path.c_str(), hostOwner, hostGroup);
668  return (result == -1) ? -errno : result;
669 }
670 
673  int tgt_fd, uint32_t owner, uint32_t group)
674 {
675  auto p = tc->getProcessPtr();
676 
677  auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
678  if (!ffdp)
679  return -EBADF;
680  int sim_fd = ffdp->getSimFD();
681 
682  /* XXX endianess */
683  uid_t hostOwner = owner;
684  gid_t hostGroup = group;
685 
686  int result = fchown(sim_fd, hostOwner, hostGroup);
687  return (result == -1) ? -errno : result;
688 }
689 
697 dupFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd)
698 {
699  auto p = tc->getProcessPtr();
700 
701  auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
702  if (!old_hbfdp)
703  return -EBADF;
704  int sim_fd = old_hbfdp->getSimFD();
705 
706  int result = dup(sim_fd);
707  if (result == -1)
708  return -errno;
709 
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);
714 }
715 
717 dup2Func(SyscallDesc *desc, int num, ThreadContext *tc,
718  int old_tgt_fd, int new_tgt_fd)
719 {
720  auto p = tc->getProcessPtr();
721  auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]);
722  if (!old_hbp)
723  return -EBADF;
724  int old_sim_fd = old_hbp->getSimFD();
725 
731  int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY));
732  if (res_fd == -1)
733  return -errno;
734 
735  auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]);
736  if (new_hbp)
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);
741 
742  return p->fds->allocFD(new_hbp);
743 }
744 
746 fcntlFunc(SyscallDesc *desc, int num, ThreadContext *tc)
747 {
748  int arg;
749  int index = 0;
750  auto p = tc->getProcessPtr();
751  int tgt_fd = p->getSyscallArg(tc, index);
752  int cmd = p->getSyscallArg(tc, index);
753 
754  auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
755  if (!hbfdp)
756  return -EBADF;
757  int sim_fd = hbfdp->getSimFD();
758 
759  int coe = hbfdp->getCOE();
760 
761  switch (cmd) {
762  case F_GETFD:
763  return coe & FD_CLOEXEC;
764 
765  case F_SETFD: {
766  arg = p->getSyscallArg(tc, index);
767  arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false);
768  return 0;
769  }
770 
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.
777  case F_GETFL:
778  case F_SETFL: {
779  arg = p->getSyscallArg(tc, index);
780  int rv = fcntl(sim_fd, cmd, arg);
781  return (rv == -1) ? -errno : rv;
782  }
783 
784  default:
785  warn("fcntl: unsupported command %d\n", cmd);
786  return 0;
787  }
788 }
789 
792 {
793  int index = 0;
794  auto p = tc->getProcessPtr();
795  int tgt_fd = p->getSyscallArg(tc, index);
796 
797  auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
798  if (!hbfdp)
799  return -EBADF;
800  int sim_fd = hbfdp->getSimFD();
801 
802  int cmd = p->getSyscallArg(tc, index);
803  switch (cmd) {
804  case 33: //F_GETLK64
805  warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
806  return -EMFILE;
807 
808  case 34: // F_SETLK64
809  case 35: // F_SETLKW64
810  warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
811  tgt_fd);
812  return -EMFILE;
813 
814  default:
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);
819  }
820 }
821 
823 pipeImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool pseudo_pipe,
824  bool is_pipe2)
825 {
826  Addr tgt_addr = 0;
827  int flags = 0;
828  auto p = tc->getProcessPtr();
829  if (!pseudo_pipe) {
830  int index = 0;
831  tgt_addr = p->getSyscallArg(tc, index);
832  if (is_pipe2) {
833  flags = p->getSyscallArg(tc, index);
834  }
835  }
836 
837  int sim_fds[2], tgt_fds[2];
838 
839  int pipe_retval = pipe(sim_fds);
840  if (pipe_retval == -1)
841  return -errno;
842 
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();
847 
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();
852 
857  rpfd->setPipeReadSource(tgt_fds[1]);
858 
863  if (pseudo_pipe) {
864  tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
865  return tgt_fds[0];
866  }
867 
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());
877 
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))) {
884  return -EINVAL;
885  }
886 
887  /*
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.
890  */
891  if (flags & O_NONBLOCK) {
892  /*
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.
897  */
898  if (fcntl(sim_fd_rpfd, F_SETFL, O_NONBLOCK)) {
899  return -errno;
900  }
901  if (fcntl(sim_fd_wpfd, F_SETFL, O_NONBLOCK)) {
902  return -errno;
903  }
904  }
905 
906  /*
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.
909  */
910  if (flags & O_CLOEXEC) {
911  rpfd->setCOE(true);
912  wpfd->setCOE(true);
913  }
914  }
915 
916  return 0;
917 }
918 
920 pipePseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
921 {
922  return pipeImpl(desc, callnum, tc, true);
923 }
924 
926 pipeFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
927 {
928  return pipeImpl(desc, callnum, tc, false);
929 }
930 
932 pipe2Func(SyscallDesc *desc, int callnum, ThreadContext *tc)
933 {
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);
937 }
938 
940 getpgrpFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
941 {
942  auto process = tc->getProcessPtr();
943  return process->pgid();
944 }
945 
947 setpgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc,
948  int pid, int pgid)
949 {
950  auto process = tc->getProcessPtr();
951 
952  if (pgid < 0)
953  return -EINVAL;
954 
955  if (pid == 0) {
956  process->pgid(process->pid());
957  return 0;
958  }
959 
960  Process *matched_ph = nullptr;
961  System *sysh = tc->getSystemPtr();
962 
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;
968 
969  if (walk_ph && walk_ph->pid() == process->pid())
970  matched_ph = walk_ph;
971  }
972  }
973 
974  assert(matched_ph);
975  matched_ph->pgid((pgid == 0) ? matched_ph->pid() : pgid);
976 
977  return 0;
978 }
979 
982 {
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.
986 
987  auto process = tc->getProcessPtr();
988  tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
989  return process->pid();
990 }
991 
992 
995 {
996  // Make up a UID and EUID... it shouldn't matter, and we want the
997  // simulation to be deterministic.
998 
999  // EUID goes in r20.
1000  auto process = tc->getProcessPtr();
1001  tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID
1002  return process->uid(); // UID
1003 }
1004 
1005 
1008 {
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();
1013 }
1014 
1015 
1017 getpidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1018 {
1019  auto process = tc->getProcessPtr();
1020  return process->tgid();
1021 }
1022 
1024 gettidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1025 {
1026  auto process = tc->getProcessPtr();
1027  return process->pid();
1028 }
1029 
1031 getppidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1032 {
1033  auto process = tc->getProcessPtr();
1034  return process->ppid();
1035 }
1036 
1038 getuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1039 {
1040  auto process = tc->getProcessPtr();
1041  return process->uid(); // UID
1042 }
1043 
1045 geteuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1046 {
1047  auto process = tc->getProcessPtr();
1048  return process->euid(); // UID
1049 }
1050 
1052 getgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1053 {
1054  auto process = tc->getProcessPtr();
1055  return process->gid();
1056 }
1057 
1059 getegidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1060 {
1061  auto process = tc->getProcessPtr();
1062  return process->egid();
1063 }
1064 
1066 fallocateFunc(SyscallDesc *desc, int callnum, ThreadContext *tc,
1067  int tgt_fd, int mode, off_t offset, off_t len)
1068 {
1069 #if defined(__linux__)
1070  auto p = tc->getProcessPtr();
1071 
1072  auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1073  if (!ffdp)
1074  return -EBADF;
1075  int sim_fd = ffdp->getSimFD();
1076 
1077  int result = fallocate(sim_fd, mode, offset, len);
1078  if (result < 0)
1079  return -errno;
1080  return 0;
1081 #else
1082  warnUnsupportedOS("fallocate");
1083  return -1;
1084 #endif
1085 }
1086 
1088 accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc,
1089  Addr pathname, mode_t mode)
1090 {
1091  string path;
1092  auto p = tc->getProcessPtr();
1093  if (!tc->getVirtProxy().tryReadString(path, pathname))
1094  return -EFAULT;
1095 
1096  // Adjust path for cwd and redirection
1097  path = p->checkPathRedirect(path);
1098 
1099  int result = access(path.c_str(), mode);
1100  return (result == -1) ? -errno : result;
1101 }
1102 
1105  Addr pathname, mode_t mode, dev_t dev)
1106 {
1107  auto p = tc->getProcessPtr();
1108  std::string path;
1109  if (!tc->getVirtProxy().tryReadString(path, pathname))
1110  return -EFAULT;
1111 
1112  path = p->checkPathRedirect(path);
1113 
1114  auto result = mknod(path.c_str(), mode, dev);
1115  return (result == -1) ? -errno : result;
1116 }
1117 
1119 chdirFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname)
1120 {
1121  auto p = tc->getProcessPtr();
1122  std::string path;
1123  if (!tc->getVirtProxy().tryReadString(path, pathname))
1124  return -EFAULT;
1125 
1126  std::string tgt_cwd;
1127  if (startswith(path, "/")) {
1128  tgt_cwd = path;
1129  } else {
1130  char buf[PATH_MAX];
1131  tgt_cwd = realpath((p->tgtCwd + "/" + path).c_str(), buf);
1132  }
1133  std::string host_cwd = p->checkPathRedirect(tgt_cwd);
1134 
1135  int result = chdir(host_cwd.c_str());
1136 
1137  if (result == -1)
1138  return -errno;
1139 
1140  p->hostCwd = host_cwd;
1141  p->tgtCwd = tgt_cwd;
1142  return result;
1143 }
1144 
1146 rmdirFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname)
1147 {
1148  auto p = tc->getProcessPtr();
1149  std::string path;
1150  if (!tc->getVirtProxy().tryReadString(path, pathname))
1151  return -EFAULT;
1152 
1153  path = p->checkPathRedirect(path);
1154 
1155  auto result = rmdir(path.c_str());
1156  return (result == -1) ? -errno : result;
1157 }
1158 
1159 #if defined(SYS_getdents) || defined(SYS_getdents64)
1160 template<typename DE, int SYS_NUM>
1161 static SyscallReturn
1162 getdentsImpl(SyscallDesc *desc, int callnum, ThreadContext *tc,
1163  int tgt_fd, Addr buf_ptr, unsigned count)
1164 {
1165  auto p = tc->getProcessPtr();
1166 
1167  auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1168  if (!hbfdp)
1169  return -EBADF;
1170  int sim_fd = hbfdp->getSimFD();
1171 
1172  BufferArg buf_arg(buf_ptr, count);
1173  auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count);
1174 
1175  if (status == -1)
1176  return -errno;
1177 
1178  unsigned traversed = 0;
1179  while (traversed < status) {
1180  DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed);
1181 
1182  auto host_reclen = buffer->d_reclen;
1183 
1189  const ByteOrder bo = tc->getSystemPtr()->getGuestByteOrder();
1190  buffer->d_ino = htog(buffer->d_ino, bo);
1191  buffer->d_off = htog(buffer->d_off, bo);
1192  buffer->d_reclen = htog(buffer->d_reclen, bo);
1193 
1194  traversed += host_reclen;
1195  }
1196 
1197  buf_arg.copyOut(tc->getVirtProxy());
1198  return status;
1199 }
1200 #endif
1201 
1202 #if defined(SYS_getdents)
1204 getdentsFunc(SyscallDesc *desc, int callnum, ThreadContext *tc,
1205  int tgt_fd, Addr buf_ptr, unsigned count)
1206 {
1207  typedef struct linux_dirent {
1208  unsigned long d_ino;
1209  unsigned long d_off;
1210  unsigned short d_reclen;
1211  char dname[];
1212  } LinDent;
1213 
1214  return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, tc,
1215  tgt_fd, buf_ptr, count);
1216 }
1217 #endif
1218 
1219 #if defined(SYS_getdents64)
1221 getdents64Func(SyscallDesc *desc, int callnum, ThreadContext *tc,
1222  int tgt_fd, Addr buf_ptr, unsigned count)
1223 {
1224  typedef struct linux_dirent64 {
1225  ino64_t d_ino;
1226  off64_t d_off;
1227  unsigned short d_reclen;
1228  char dname[];
1229  } LinDent64;
1230 
1231  return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, tc,
1232  tgt_fd, buf_ptr, count);
1233 }
1234 #endif
1235 
1238  int tgt_fd, int how)
1239 {
1240  auto p = tc->getProcessPtr();
1241 
1242  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1243  if (!sfdp)
1244  return -EBADF;
1245  int sim_fd = sfdp->getSimFD();
1246 
1247  int retval = shutdown(sim_fd, how);
1248 
1249  return (retval == -1) ? -errno : retval;
1250 }
1251 
1253 bindFunc(SyscallDesc *desc, int num, ThreadContext *tc,
1254  int tgt_fd, Addr buf_ptr, int addrlen)
1255 {
1256  auto p = tc->getProcessPtr();
1257 
1258  BufferArg bufSock(buf_ptr, addrlen);
1259  bufSock.copyIn(tc->getVirtProxy());
1260 
1261  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1262  if (!sfdp)
1263  return -EBADF;
1264  int sim_fd = sfdp->getSimFD();
1265 
1266  int status = ::bind(sim_fd,
1267  (struct sockaddr *)bufSock.bufferPtr(),
1268  addrlen);
1269 
1270  return (status == -1) ? -errno : status;
1271 }
1272 
1275  int tgt_fd, int backlog)
1276 {
1277  auto p = tc->getProcessPtr();
1278 
1279  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1280  if (!sfdp)
1281  return -EBADF;
1282  int sim_fd = sfdp->getSimFD();
1283 
1284  int status = listen(sim_fd, backlog);
1285 
1286  return (status == -1) ? -errno : status;
1287 }
1288 
1291  int tgt_fd, Addr buf_ptr, int addrlen)
1292 {
1293  auto p = tc->getProcessPtr();
1294 
1295  BufferArg addr(buf_ptr, addrlen);
1296  addr.copyIn(tc->getVirtProxy());
1297 
1298  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1299  if (!sfdp)
1300  return -EBADF;
1301  int sim_fd = sfdp->getSimFD();
1302 
1303  int status = connect(sim_fd,
1304  (struct sockaddr *)addr.bufferPtr(),
1305  (socklen_t)addrlen);
1306 
1307  return (status == -1) ? -errno : status;
1308 }
1309 
1312  int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags,
1313  Addr addrPtr, Addr addrlenPtr)
1314 {
1315  auto p = tc->getProcessPtr();
1316 
1317  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1318  if (!sfdp)
1319  return -EBADF;
1320  int sim_fd = sfdp->getSimFD();
1321 
1322  // Reserve buffer space.
1323  BufferArg bufrBuf(bufrPtr, bufrLen);
1324 
1325  // Get address length.
1326  socklen_t addrLen = 0;
1327  if (addrlenPtr != 0) {
1328  // Read address length parameter.
1329  BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1330  addrlenBuf.copyIn(tc->getVirtProxy());
1331  addrLen = *((socklen_t *)addrlenBuf.bufferPtr());
1332  }
1333 
1334  struct sockaddr sa, *sap = NULL;
1335  if (addrLen != 0) {
1336  BufferArg addrBuf(addrPtr, addrLen);
1337  addrBuf.copyIn(tc->getVirtProxy());
1338  memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(),
1339  sizeof(struct sockaddr));
1340  sap = &sa;
1341  }
1342 
1343  ssize_t recvd_size = recvfrom(sim_fd,
1344  (void *)bufrBuf.bufferPtr(),
1345  bufrLen, flags, sap, (socklen_t *)&addrLen);
1346 
1347  if (recvd_size == -1)
1348  return -errno;
1349 
1350  // Pass the received data out.
1351  bufrBuf.copyOut(tc->getVirtProxy());
1352 
1353  // Copy address to addrPtr and pass it on.
1354  if (sap != NULL) {
1355  BufferArg addrBuf(addrPtr, addrLen);
1356  memcpy(addrBuf.bufferPtr(), sap, sizeof(sa));
1357  addrBuf.copyOut(tc->getVirtProxy());
1358  }
1359 
1360  // Copy len to addrlenPtr and pass it on.
1361  if (addrLen != 0) {
1362  BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1363  *(socklen_t *)addrlenBuf.bufferPtr() = addrLen;
1364  addrlenBuf.copyOut(tc->getVirtProxy());
1365  }
1366 
1367  return recvd_size;
1368 }
1369 
1372  int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags,
1373  Addr addrPtr, socklen_t addrLen)
1374 {
1375  auto p = tc->getProcessPtr();
1376 
1377  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1378  if (!sfdp)
1379  return -EBADF;
1380  int sim_fd = sfdp->getSimFD();
1381 
1382  // Reserve buffer space.
1383  BufferArg bufrBuf(bufrPtr, bufrLen);
1384  bufrBuf.copyIn(tc->getVirtProxy());
1385 
1386  struct sockaddr sa, *sap = nullptr;
1387  memset(&sa, 0, sizeof(sockaddr));
1388  if (addrLen != 0) {
1389  BufferArg addrBuf(addrPtr, addrLen);
1390  addrBuf.copyIn(tc->getVirtProxy());
1391  memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen);
1392  sap = &sa;
1393  }
1394 
1395  ssize_t sent_size = sendto(sim_fd,
1396  (void *)bufrBuf.bufferPtr(),
1397  bufrLen, flags, sap, (socklen_t)addrLen);
1398 
1399  return (sent_size == -1) ? -errno : sent_size;
1400 }
1401 
1404  int tgt_fd, Addr msgPtr, int flags)
1405 {
1406  auto p = tc->getProcessPtr();
1407 
1408  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1409  if (!sfdp)
1410  return -EBADF;
1411  int sim_fd = sfdp->getSimFD();
1412 
1436  BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1437  msgBuf.copyIn(tc->getVirtProxy());
1438  struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr();
1439 
1445  Addr msg_name_phold = 0;
1446  Addr msg_iov_phold = 0;
1447  Addr iovec_base_phold[msgHdr->msg_iovlen];
1448  Addr msg_control_phold = 0;
1449 
1453  BufferArg *nameBuf = NULL;
1454  if (msgHdr->msg_name) {
1455  /*1*/msg_name_phold = (Addr)msgHdr->msg_name;
1456  /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen);
1457  /*3*/nameBuf->copyIn(tc->getVirtProxy());
1458  /*4*/msgHdr->msg_name = nameBuf->bufferPtr();
1459  }
1460 
1466  BufferArg *iovBuf = NULL;
1467  BufferArg *iovecBuf[msgHdr->msg_iovlen];
1468  for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1469  iovec_base_phold[i] = 0;
1470  iovecBuf[i] = NULL;
1471  }
1472 
1473  if (msgHdr->msg_iov) {
1474  /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov;
1475  /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen *
1476  sizeof(struct iovec));
1477  /*3*/iovBuf->copyIn(tc->getVirtProxy());
1478  for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1479  if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1480  /*1*/iovec_base_phold[i] =
1481  (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base;
1482  /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i],
1483  ((struct iovec *)iovBuf->bufferPtr())[i].iov_len);
1484  /*3*/iovecBuf[i]->copyIn(tc->getVirtProxy());
1485  /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1486  iovecBuf[i]->bufferPtr();
1487  }
1488  }
1489  /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr();
1490  }
1491 
1495  BufferArg *controlBuf = NULL;
1496  if (msgHdr->msg_control) {
1497  /*1*/msg_control_phold = (Addr)msgHdr->msg_control;
1498  /*2*/controlBuf = new BufferArg(msg_control_phold,
1499  CMSG_ALIGN(msgHdr->msg_controllen));
1500  /*3*/controlBuf->copyIn(tc->getVirtProxy());
1501  /*4*/msgHdr->msg_control = controlBuf->bufferPtr();
1502  }
1503 
1504  ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags);
1505 
1506  if (recvd_size < 0)
1507  return -errno;
1508 
1509  if (msgHdr->msg_name) {
1510  nameBuf->copyOut(tc->getVirtProxy());
1511  delete(nameBuf);
1512  msgHdr->msg_name = (void *)msg_name_phold;
1513  }
1514 
1515  if (msgHdr->msg_iov) {
1516  for (int i = 0; i< msgHdr->msg_iovlen; i++) {
1517  if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1518  iovecBuf[i]->copyOut(tc->getVirtProxy());
1519  delete iovecBuf[i];
1520  ((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1521  (void *)iovec_base_phold[i];
1522  }
1523  }
1524  iovBuf->copyOut(tc->getVirtProxy());
1525  delete iovBuf;
1526  msgHdr->msg_iov = (struct iovec *)msg_iov_phold;
1527  }
1528 
1529  if (msgHdr->msg_control) {
1530  controlBuf->copyOut(tc->getVirtProxy());
1531  delete(controlBuf);
1532  msgHdr->msg_control = (void *)msg_control_phold;
1533  }
1534 
1535  msgBuf.copyOut(tc->getVirtProxy());
1536 
1537  return recvd_size;
1538 }
1539 
1542  int tgt_fd, Addr msgPtr, int flags)
1543 {
1544  auto p = tc->getProcessPtr();
1545 
1546  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1547  if (!sfdp)
1548  return -EBADF;
1549  int sim_fd = sfdp->getSimFD();
1550 
1554  BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1555  msgBuf.copyIn(tc->getVirtProxy());
1556  struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr());
1557 
1562  struct iovec *iovPtr = msgHdr.msg_iov;
1563  BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen);
1564  iovBuf.copyIn(tc->getVirtProxy());
1565  struct iovec *iov = (struct iovec *)iovBuf.bufferPtr();
1566  msgHdr.msg_iov = iov;
1567 
1573  BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen
1574  * sizeof(BufferArg *));
1575 
1581  for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1582  Addr basePtr = (Addr) iov[iovIndex].iov_base;
1583  bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len);
1584  bufferArray[iovIndex]->copyIn(tc->getVirtProxy());
1585  iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr();
1586  }
1587 
1588  ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags);
1589  int local_errno = errno;
1590 
1594  for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1595  BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex];
1596  delete(baseBuf);
1597  }
1598 
1602  free(bufferArray);
1603 
1604  return (sent_size < 0) ? -local_errno : sent_size;
1605 }
1606 
1609  int tgt_fd, int level, int optname, Addr valPtr, Addr lenPtr)
1610 {
1611  // union of all possible return value types from getsockopt
1612  union val {
1613  int i_val;
1614  long l_val;
1615  struct linger linger_val;
1616  struct timeval timeval_val;
1617  } val;
1618 
1619  auto p = tc->getProcessPtr();
1620 
1621  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1622  if (!sfdp)
1623  return -EBADF;
1624  int sim_fd = sfdp->getSimFD();
1625 
1626  socklen_t len = sizeof(val);
1627  int status = getsockopt(sim_fd, level, optname, &val, &len);
1628 
1629  if (status == -1)
1630  return -errno;
1631 
1632  // copy val to valPtr and pass it on
1633  BufferArg valBuf(valPtr, sizeof(val));
1634  memcpy(valBuf.bufferPtr(), &val, sizeof(val));
1635  valBuf.copyOut(tc->getVirtProxy());
1636 
1637  // copy len to lenPtr and pass it on
1638  BufferArg lenBuf(lenPtr, sizeof(len));
1639  memcpy(lenBuf.bufferPtr(), &len, sizeof(len));
1640  lenBuf.copyOut(tc->getVirtProxy());
1641 
1642  return status;
1643 }
1644 
1647  int tgt_fd, Addr addrPtr, Addr lenPtr)
1648 {
1649  auto p = tc->getProcessPtr();
1650 
1651  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1652  if (!sfdp)
1653  return -EBADF;
1654  int sim_fd = sfdp->getSimFD();
1655 
1656  // lenPtr is an in-out paramenter:
1657  // sending the address length in, conveying the final length out
1658 
1659  // Read in the value of len from the passed pointer.
1660  BufferArg lenBuf(lenPtr, sizeof(socklen_t));
1661  lenBuf.copyIn(tc->getVirtProxy());
1662  socklen_t len = *(socklen_t *)lenBuf.bufferPtr();
1663 
1664  struct sockaddr sa;
1665  int status = getsockname(sim_fd, &sa, &len);
1666 
1667  if (status == -1)
1668  return -errno;
1669 
1670  // Copy address to addrPtr and pass it on.
1671  BufferArg addrBuf(addrPtr, sizeof(sa));
1672  memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa));
1673  addrBuf.copyOut(tc->getVirtProxy());
1674 
1675  // Copy len to lenPtr and pass it on.
1676  *(socklen_t *)lenBuf.bufferPtr() = len;
1677  lenBuf.copyOut(tc->getVirtProxy());
1678 
1679  return status;
1680 }
1681 
1684  int tgt_fd, Addr sockAddrPtr, Addr addrlenPtr)
1685 {
1686  auto p = tc->getProcessPtr();
1687 
1688  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1689  if (!sfdp)
1690  return -EBADF;
1691  int sim_fd = sfdp->getSimFD();
1692 
1693  BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned));
1694  bufAddrlen.copyIn(tc->getVirtProxy());
1695  BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr());
1696 
1697  int retval = getpeername(sim_fd,
1698  (struct sockaddr *)bufSock.bufferPtr(),
1699  (unsigned *)bufAddrlen.bufferPtr());
1700 
1701  if (retval != -1) {
1702  bufSock.copyOut(tc->getVirtProxy());
1703  bufAddrlen.copyOut(tc->getVirtProxy());
1704  }
1705 
1706  return (retval == -1) ? -errno : retval;
1707 }
1708 
1711  int tgt_fd, int level, int optname, Addr valPtr, socklen_t len)
1712 {
1713  auto p = tc->getProcessPtr();
1714 
1715  BufferArg valBuf(valPtr, len);
1716  valBuf.copyIn(tc->getVirtProxy());
1717 
1718  auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1719  if (!sfdp)
1720  return -EBADF;
1721  int sim_fd = sfdp->getSimFD();
1722 
1723  int status = setsockopt(sim_fd, level, optname,
1724  (struct sockaddr *)valBuf.bufferPtr(), len);
1725 
1726  return (status == -1) ? -errno : status;
1727 }
1728 
count
Definition: misc.hh:705
FutexMap futexMap
Definition: system.hh:642
virtual void halt()=0
Set the status to Halted.
virtual System * getSystemPtr()=0
Bitfield< 30, 0 > index
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:175
const std::string & name()
Definition: trace.cc:54
uint64_t childClearTID
Calls a futex wakeup at the address specified by this pointer when this process exits.
Definition: process.hh:289
Bitfield< 7 > i
SyscallReturn geteuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target geteuid() handler.
SyscallReturn ignoreFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Handler for unimplemented syscalls that we never intend to implement (signal handling, etc.) and should not affect the correct behavior of the program.
Definition: syscall_emul.cc:77
Trying to exit and waiting for an event to completely exit.
SyscallReturn dup2Func(SyscallDesc *desc, int num, ThreadContext *tc, int old_tgt_fd, int new_tgt_fd)
Target dup2() handler.
SyscallReturn getcwdFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr buf_ptr, unsigned long size)
Target getcwd() handler.
static SyscallReturn exitImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool group, int status)
bool copyIn(PortProxy &memproxy)
copy data into simulator space (read from target memory)
ip6_addr_t addr
Definition: inet.hh:335
uint64_t uid()
Definition: process.hh:87
virtual PortProxy & getVirtProxy()=0
std::string name()
Definition: syscall_desc.hh:88
virtual Process * getProcessPtr()=0
Holds file descriptors for host-backed files; host-backed files are files which were opened on the ph...
Definition: fd_entry.hh:112
Definition: system.hh:77
SyscallReturn fcntlFunc(SyscallDesc *desc, int num, ThreadContext *tc)
Target fcntl() handler.
Bitfield< 23, 0 > offset
Definition: types.hh:154
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:586
ByteOrder getGuestByteOrder() const
Get the guest byte order.
Definition: system.hh:293
SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getuidPseudo() handler.
SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getgidPseudo() handler.
Bitfield< 4, 0 > mode
const char * hostname
T roundUp(const T &val, const U &align)
This function is used to align addresses in memory.
Definition: intmath.hh:168
SyscallReturn fallocateFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int tgt_fd, int mode, off_t offset, off_t len)
ThreadContext is the external interface to all thread state for anything outside of the CPU...
#define DPRINTF_SYSCALL(FLAGEXT, FMT,...)
This macro is intended to help with readability.
SyscallReturn sendtoFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags, Addr addrPtr, socklen_t addrLen)
SyscallReturn closeFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd)
Target close() handler.
SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr buf_ptr, int name_len)
Target gethostname() handler.
Bitfield< 63 > val
Definition: misc.hh:771
SyscallReturn getegidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getegid() handler.
SyscallReturn renameFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr oldpath, Addr newpath)
Target rename() handler.
SyscallReturn umaskFunc(SyscallDesc *desc, int num, ThreadContext *tc)
Target umask() handler.
Bitfield< 5, 0 > status
SyscallReturn pipe2Func(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target pipe() handler.
SyscallReturn munmapFunc(SyscallDesc *desc, int num, ThreadContext *tc)
Target munmap() handler.
SyscallReturn chdirFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname)
Target chdir() handler.
SyscallReturn getuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
SyscallReturn getpeernameFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr sockAddrPtr, Addr addrlenPtr)
SyscallReturn unlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname)
Target unlink() handler.
SyscallReturn fchownFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, uint32_t owner, uint32_t group)
Target fchown() handler.
SyscallReturn exitGroupFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int status)
Target exit_group() handler: terminate simulation. (exit all threads)
T htog(T value, ByteOrder guest_byte_order)
Definition: byteswap.hh:159
SyscallReturn mkdirFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, mode_t mode)
Target mkdir() handler.
SyscallReturn getsocknameFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr addrPtr, Addr lenPtr)
uint64_t ppid()
Definition: process.hh:92
SyscallReturn _llseekFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, uint64_t offset_high, uint32_t offset_low, Addr result_ptr, int whence)
Target _llseek() handler.
void memsetBlob(Addr addr, uint8_t v, int size) const
Same as tryMemsetBlob, but insists on success.
Definition: port_proxy.hh:199
int wakeup(Addr addr, uint64_t tgid, int count)
Wakes up at most count waiting threads on a futex.
Definition: futex_map.hh:144
SyscallReturn shutdownFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, int how)
Target shutdown() handler.
uint64_t pid()
Definition: process.hh:91
This class takes an arbitrary memory region (address/length pair) and generates a series of appropria...
SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getpidPseudo() handler.
ByteOrder
Definition: types.hh:247
SyscallReturn recvfromFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags, Addr addrPtr, Addr addrlenPtr)
uint64_t euid()
Definition: process.hh:88
SyscallReturn setsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, int level, int optname, Addr valPtr, socklen_t len)
SyscallReturn readlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, Addr buf_ptr, size_t bufsiz)
Target readlink() handler.
SyscallReturn mknodFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, mode_t mode, dev_t dev)
Target mknod() handler.
Bitfield< 3 > sa
std::vector< ThreadContext * > threadContexts
Definition: system.hh:190
SyscallReturn rmdirFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname)
Bitfield< 18, 16 > len
Extends the base class to include a host-backed file descriptor field that records the integer used t...
Definition: fd_entry.hh:76
unsigned numContexts() const
Definition: system.hh:206
void * bufferPtr()
Return a pointer to the internal simulator-space buffer.
SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, off_t length)
Target ftruncate() handler.
T roundDown(const T &val, const U &align)
This function is used to align addresses in memory.
Definition: intmath.hh:185
SyscallReturn getppidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getppid() handler.
const RegIndex SyscallPseudoReturnReg
Definition: registers.hh:86
static bool readyToExit(Tick delay)
Initiate the exit from the simulation.
Definition: dist_iface.cc:898
SyscallReturn brkFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr new_brk)
Target brk() handler: set brk address.
SyscallReturn pipeImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool pseudo_pipe, bool is_pipe2)
Internal pipe() handler.
uint64_t pgid()
Definition: process.hh:93
virtual void setIntReg(RegIndex reg_idx, RegVal val)=0
SyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num, ThreadContext *tc)
Like above, but only prints a warning once per syscall desc it&#39;s used with.
Definition: syscall_emul.cc:84
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
SyscallReturn dupFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd)
FIXME: The file description is not shared among file descriptors created with dup.
SyscallReturn unimplementedFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Handler for unimplemented syscalls that we haven&#39;t thought about.
Definition: syscall_emul.cc:68
bool done() const
Are we done? That is, did the last call to next() advance past the end of the region?
SyscallReturn getgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getgid() handler.
SyscallReturn linkFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, Addr new_pathname)
Target link() handler.
SyscallReturn sendmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr msgPtr, int flags)
#define warn_once(...)
Definition: logging.hh:216
std::list< BasicSignal > signalList
Definition: system.hh:651
bool startswith(const char *s, const char *prefix)
Return true if &#39;s&#39; starts with the prefix string &#39;prefix&#39;.
Definition: str.hh:227
const Addr PageBytes
Definition: isa_traits.hh:47
Bitfield< 15 > system
Definition: misc.hh:999
SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, ThreadContext *tc)
Target getpagesize() handler.
SyscallReturn listenFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, int backlog)
SyscallReturn getpgrpFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getpgrpFunc() handler.
Bitfield< 20 > level
Definition: intmessage.hh:49
This class provides the wrapper interface for the system call implementations which are defined in th...
Definition: syscall_desc.hh:69
SyscallReturn gettidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target gettid() handler.
This object is a proxy for a port or other object which implements the functional response protocol...
Definition: port_proxy.hh:82
SyscallReturn truncateFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, off_t length)
Target truncate() handler.
SyscallReturn fcntl64Func(SyscallDesc *desc, int num, ThreadContext *tc)
Target fcntl64() handler.
SyscallReturn getsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, int level, int optname, Addr valPtr, Addr lenPtr)
SyscallReturn lseekFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, uint64_t offs, int whence)
Target lseek() handler.
SyscallReturn pipeFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target pipe() handler.
void exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat, bool serialize)
Schedule an event to exit the simulation loop (returning to Python) at the end of the current cycle (...
Definition: sim_events.cc:90
Bitfield< 25, 21 > bo
Definition: types.hh:64
Declarations of a non-full system Page Table.
SyscallReturn accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, Addr pathname, mode_t mode)
Target access() handler.
SyscallReturn symlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, Addr new_pathname)
Target symlink() handler.
This file defines objects used to emulate syscalls from the target application on the host machine...
Permanently shut down.
SyscallReturn setTidAddressFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, uint64_t tidPtr)
Target set_tid_address() handler.
std::string checkPathRedirect(const std::string &filename)
Redirect file path if it matches any keys initialized by system object.
Definition: process.cc:459
SyscallReturn connectFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr buf_ptr, int addrlen)
bool copyOut(PortProxy &memproxy)
copy data out of simulator space (write to target memory)
SyscallReturn setpgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int pid, int pgid)
Target setpgid() handler.
FutexMap class holds a map of all futexes used in the system.
Definition: futex_map.hh:121
uint64_t gid()
Definition: process.hh:89
SyscallReturn chownFunc(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, uint32_t owner, uint32_t group)
Target chown() handler.
SyscallReturn recvmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr msgPtr, int flags)
BufferArg represents an untyped buffer in target user space that is passed by reference to an (emulat...
SyscallReturn truncate64Func(SyscallDesc *desc, int num, ThreadContext *tc, Addr pathname, int64_t length)
Target truncate64() handler.
uint8_t length
Definition: inet.hh:334
SyscallReturn bindFunc(SyscallDesc *desc, int num, ThreadContext *tc, int tgt_fd, Addr buf_ptr, int addrlen)
#define warn(...)
Definition: logging.hh:212
SyscallReturn pipePseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Pseudo Funcs - These functions use a different return convension, returning a second value in a regis...
Declaration and inline definition of ChunkGenerator object.
This class represents the return value from an emulated system call, including any errno setting...
void warnUnsupportedOS(std::string syscall_name)
Definition: syscall_emul.cc:62
uint64_t tgid()
Definition: process.hh:95
bool tryReadString(std::string &str, Addr addr) const
Reads the string at guest address addr into the std::string str.
Definition: port_proxy.cc:102
Bitfield< 0 > p
static void exitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid)
Definition: syscall_emul.cc:99
SyscallReturn getpidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
Target getpid() handler.
SyscallReturn exitFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int status)
Target exit() handler: terminate current context.
uint64_t egid()
Definition: process.hh:90
SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, ThreadContext *tc)
Target ftruncate64() handler.
static std::vector< System * > systemList
Definition: system.hh:637

Generated on Fri Feb 28 2020 16:27:03 for gem5 by doxygen 1.8.13