arch-arm: Remove some unused vars from self_debug.hh
[gem5.git] / src / sim / syscall_emul.cc
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
29 #include "sim/syscall_emul.hh"
30
31 #include <fcntl.h>
32 #include <sys/syscall.h>
33 #include <unistd.h>
34
35 #include <csignal>
36 #include <iostream>
37 #include <mutex>
38 #include <string>
39 #include <unordered_map>
40
41 #include "arch/utility.hh"
42 #include "base/chunk_generator.hh"
43 #include "base/trace.hh"
44 #include "config/the_isa.hh"
45 #include "cpu/thread_context.hh"
46 #include "dev/net/dist_iface.hh"
47 #include "mem/page_table.hh"
48 #include "sim/byteswap.hh"
49 #include "sim/process.hh"
50 #include "sim/sim_exit.hh"
51 #include "sim/syscall_debug_macros.hh"
52 #include "sim/syscall_desc.hh"
53 #include "sim/system.hh"
54
55 using namespace std;
56 using namespace TheISA;
57
58 void
59 warnUnsupportedOS(std::string syscall_name)
60 {
61 warn("Cannot invoke %s on host operating system.", syscall_name);
62 }
63
64 SyscallReturn
65 unimplementedFunc(SyscallDesc *desc, ThreadContext *tc)
66 {
67 fatal("syscall %s (#%d) unimplemented.", desc->name(), desc->num());
68 }
69
70
71 SyscallReturn
72 ignoreFunc(SyscallDesc *desc, ThreadContext *tc)
73 {
74 warn("ignoring syscall %s(...)", desc->name());
75 return 0;
76 }
77
78 SyscallReturn
79 ignoreWarnOnceFunc(SyscallDesc *desc, ThreadContext *tc)
80 {
81 static std::unordered_map<SyscallDesc *, bool> bool_map;
82
83 bool &warned = bool_map[desc];
84 if (!warned) {
85 warn("ignoring syscall %s(...)\n"
86 " (further warnings will be suppressed)", desc->name());
87 warned = true;
88 }
89
90 return 0;
91 }
92
93 static void
94 exitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid)
95 {
96 // Clear value at address pointed to by thread's childClearTID field.
97 BufferArg ctidBuf(addr, sizeof(long));
98 long *ctid = (long *)ctidBuf.bufferPtr();
99 *ctid = 0;
100 ctidBuf.copyOut(tc->getVirtProxy());
101
102 FutexMap &futex_map = tc->getSystemPtr()->futexMap;
103 // Wake one of the waiting threads.
104 futex_map.wakeup(addr, tgid, 1);
105 }
106
107 static SyscallReturn
108 exitImpl(SyscallDesc *desc, ThreadContext *tc, bool group, int status)
109 {
110 auto p = tc->getProcessPtr();
111
112 System *sys = tc->getSystemPtr();
113
114 if (group)
115 *p->exitGroup = true;
116
117 if (p->childClearTID)
118 exitFutexWake(tc, p->childClearTID, p->tgid());
119
120 bool last_thread = true;
121 Process *parent = nullptr, *tg_lead = nullptr;
122 for (int i = 0; last_thread && i < sys->threads.size(); i++) {
123 Process *walk;
124 if (!(walk = sys->threads[i]->getProcessPtr()))
125 continue;
126
127 /**
128 * Threads in a thread group require special handing. For instance,
129 * we send the SIGCHLD signal so that it appears that it came from
130 * the head of the group. We also only delete file descriptors if
131 * we are the last thread in the thread group.
132 */
133 if (walk->pid() == p->tgid())
134 tg_lead = walk;
135
136 auto *tc = sys->threads[i];
137 if ((tc->status() != ThreadContext::Halted) &&
138 (tc->status() != ThreadContext::Halting) &&
139 (walk != p)) {
140 /**
141 * Check if we share thread group with the pointer; this denotes
142 * that we are not the last thread active in the thread group.
143 * Note that setting this to false also prevents further
144 * iterations of the loop.
145 */
146 if (walk->tgid() == p->tgid()) {
147 /**
148 * If p is trying to exit_group and both walk and p are in
149 * the same thread group (i.e., sharing the same tgid),
150 * we need to halt walk's thread context. After all threads
151 * except p are halted, p becomes the last thread in the
152 * group.
153 *
154 * If p is not doing exit_group and there exists another
155 * active thread context in the group, last_thread is
156 * set to false to prevent the parent thread from killing
157 * all threads in the group.
158 */
159 if (*(p->exitGroup)) {
160 tc->halt();
161 } else {
162 last_thread = false;
163 }
164 }
165
166 /**
167 * A corner case exists which involves execve(). After execve(),
168 * the execve will enable SIGCHLD in the process. The problem
169 * occurs when the exiting process is the root process in the
170 * system; there is no parent to receive the signal. We obviate
171 * this problem by setting the root process' ppid to zero in the
172 * Python configuration files. We really should handle the
173 * root/execve specific case more gracefully.
174 */
175 if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid()))
176 parent = walk;
177 }
178 }
179
180 if (last_thread) {
181 if (parent) {
182 assert(tg_lead);
183 sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD));
184 }
185
186 /**
187 * Run though FD array of the exiting process and close all file
188 * descriptors except for the standard file descriptors.
189 * (The standard file descriptors are shared with gem5.)
190 */
191 for (int i = 0; i < p->fds->getSize(); i++) {
192 if ((*p->fds)[i])
193 p->fds->closeFDEntry(i);
194 }
195 }
196
197 tc->halt();
198
199 /**
200 * check to see if there is no more active thread in the system. If so,
201 * exit the simulation loop
202 */
203 int activeContexts = 0;
204 for (auto &system: sys->systemList)
205 activeContexts += system->threads.numRunning();
206
207 if (activeContexts == 0) {
208 /**
209 * Even though we are terminating the final thread context, dist-gem5
210 * requires the simulation to remain active and provide
211 * synchronization messages to the switch process. So we just halt
212 * the last thread context and return. The simulation will be
213 * terminated by dist-gem5 in a coordinated manner once all nodes
214 * have signaled their readiness to exit. For non dist-gem5
215 * simulations, readyToExit() always returns true.
216 */
217 if (!DistIface::readyToExit(0)) {
218 return status;
219 }
220
221 exitSimLoop("exiting with last active thread context", status & 0xff);
222 return status;
223 }
224
225 return status;
226 }
227
228 SyscallReturn
229 exitFunc(SyscallDesc *desc, ThreadContext *tc, int status)
230 {
231 return exitImpl(desc, tc, false, status);
232 }
233
234 SyscallReturn
235 exitGroupFunc(SyscallDesc *desc, ThreadContext *tc, int status)
236 {
237 return exitImpl(desc, tc, true, status);
238 }
239
240 SyscallReturn
241 getpagesizeFunc(SyscallDesc *desc, ThreadContext *tc)
242 {
243 return (int)PageBytes;
244 }
245
246
247 SyscallReturn
248 brkFunc(SyscallDesc *desc, ThreadContext *tc, Addr new_brk)
249 {
250 // change brk addr to first arg
251 auto p = tc->getProcessPtr();
252
253 std::shared_ptr<MemState> mem_state = p->memState;
254 Addr brk_point = mem_state->getBrkPoint();
255
256 // in Linux at least, brk(0) returns the current break value
257 // (note that the syscall and the glibc function have different behavior)
258 if (new_brk == 0 || (new_brk == brk_point))
259 return brk_point;
260
261 mem_state->updateBrkRegion(brk_point, new_brk);
262
263 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
264 mem_state->getBrkPoint());
265
266 return mem_state->getBrkPoint();
267 }
268
269 SyscallReturn
270 setTidAddressFunc(SyscallDesc *desc, ThreadContext *tc, uint64_t tidPtr)
271 {
272 auto process = tc->getProcessPtr();
273
274 process->childClearTID = tidPtr;
275 return process->pid();
276 }
277
278 SyscallReturn
279 closeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd)
280 {
281 auto p = tc->getProcessPtr();
282 return p->fds->closeFDEntry(tgt_fd);
283 }
284
285 SyscallReturn
286 lseekFunc(SyscallDesc *desc, ThreadContext *tc,
287 int tgt_fd, uint64_t offs, int whence)
288 {
289 auto p = tc->getProcessPtr();
290
291 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
292 if (!ffdp)
293 return -EBADF;
294 int sim_fd = ffdp->getSimFD();
295
296 off_t result = lseek(sim_fd, offs, whence);
297
298 return (result == (off_t)-1) ? -errno : result;
299 }
300
301
302 SyscallReturn
303 _llseekFunc(SyscallDesc *desc, ThreadContext *tc,
304 int tgt_fd, uint64_t offset_high, uint32_t offset_low,
305 Addr result_ptr, int whence)
306 {
307 auto p = tc->getProcessPtr();
308
309 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
310 if (!ffdp)
311 return -EBADF;
312 int sim_fd = ffdp->getSimFD();
313
314 uint64_t offset = (offset_high << 32) | offset_low;
315
316 uint64_t result = lseek(sim_fd, offset, whence);
317 result = htog(result, tc->getSystemPtr()->getGuestByteOrder());
318
319 if (result == (off_t)-1)
320 return -errno;
321 // Assuming that the size of loff_t is 64 bits on the target platform
322 BufferArg result_buf(result_ptr, sizeof(result));
323 memcpy(result_buf.bufferPtr(), &result, sizeof(result));
324 result_buf.copyOut(tc->getVirtProxy());
325 return 0;
326 }
327
328
329 SyscallReturn
330 munmapFunc(SyscallDesc *desc, ThreadContext *tc, Addr start, size_t length)
331 {
332 // Even if the system is currently not capable of recycling physical
333 // pages, there is no reason we can't unmap them so that we trigger
334 // appropriate seg faults when the application mistakenly tries to
335 // access them again.
336 auto p = tc->getProcessPtr();
337
338 if (start & (tc->getSystemPtr()->getPageBytes() - 1) || !length) {
339 return -EINVAL;
340 }
341
342 length = roundUp(length, tc->getSystemPtr()->getPageBytes());
343
344 p->memState->unmapRegion(start, length);
345
346 return 0;
347 }
348
349
350 const char *hostname = "m5.eecs.umich.edu";
351
352 SyscallReturn
353 gethostnameFunc(SyscallDesc *desc, ThreadContext *tc,
354 Addr buf_ptr, int name_len)
355 {
356 BufferArg name(buf_ptr, name_len);
357 strncpy((char *)name.bufferPtr(), hostname, name_len);
358 name.copyOut(tc->getVirtProxy());
359 return 0;
360 }
361
362 SyscallReturn
363 getcwdFunc(SyscallDesc *desc, ThreadContext *tc,
364 Addr buf_ptr, unsigned long size)
365 {
366 int result = 0;
367 auto p = tc->getProcessPtr();
368 BufferArg buf(buf_ptr, size);
369
370 // Is current working directory defined?
371 string cwd = p->tgtCwd;
372 if (!cwd.empty()) {
373 if (cwd.length() >= size) {
374 // Buffer too small
375 return -ERANGE;
376 }
377 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
378 result = cwd.length();
379 } else {
380 if (getcwd((char *)buf.bufferPtr(), size)) {
381 result = strlen((char *)buf.bufferPtr());
382 } else {
383 result = -1;
384 }
385 }
386
387 buf.copyOut(tc->getVirtProxy());
388
389 return (result == -1) ? -errno : result;
390 }
391
392 SyscallReturn
393 readlinkFunc(SyscallDesc *desc, ThreadContext *tc,
394 Addr pathname, Addr buf_ptr, size_t bufsiz)
395 {
396 string path;
397 auto p = tc->getProcessPtr();
398
399 if (!tc->getVirtProxy().tryReadString(path, pathname))
400 return -EFAULT;
401
402 // Adjust path for cwd and redirection
403 path = p->checkPathRedirect(path);
404
405 BufferArg buf(buf_ptr, bufsiz);
406
407 int result = -1;
408 if (path != "/proc/self/exe") {
409 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
410 } else {
411 // Emulate readlink() called on '/proc/self/exe' should return the
412 // absolute path of the binary running in the simulated system (the
413 // Process' executable). It is possible that using this path in
414 // the simulated system will result in unexpected behavior if:
415 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
416 // called binary calls readlink().
417 // 2) The host's full path to the running benchmark changes from one
418 // simulation to another. This can result in different simulated
419 // performance since the simulated system will process the binary
420 // path differently, even if the binary itself does not change.
421
422 // Get the absolute canonical path to the running application
423 char real_path[PATH_MAX];
424 char *check_real_path = realpath(p->progName(), real_path);
425 if (!check_real_path) {
426 fatal("readlink('/proc/self/exe') unable to resolve path to "
427 "executable: %s", p->progName());
428 }
429 strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
430 size_t real_path_len = strlen(real_path);
431 if (real_path_len > bufsiz) {
432 // readlink will truncate the contents of the
433 // path to ensure it is no more than bufsiz
434 result = bufsiz;
435 } else {
436 result = real_path_len;
437 }
438
439 // Issue a warning about potential unexpected results
440 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
441 "results in various settings.\n Returning '%s'\n",
442 (char*)buf.bufferPtr());
443 }
444
445 buf.copyOut(tc->getVirtProxy());
446
447 return (result == -1) ? -errno : result;
448 }
449
450 SyscallReturn
451 unlinkFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname)
452 {
453 string path;
454 auto p = tc->getProcessPtr();
455
456 if (!tc->getVirtProxy().tryReadString(path, pathname))
457 return -EFAULT;
458
459 path = p->checkPathRedirect(path);
460
461 int result = unlink(path.c_str());
462 return (result == -1) ? -errno : result;
463 }
464
465 SyscallReturn
466 linkFunc(SyscallDesc *desc, ThreadContext *tc,
467 Addr pathname, Addr new_pathname)
468 {
469 string path;
470 string new_path;
471 auto p = tc->getProcessPtr();
472
473 auto &virt_mem = tc->getVirtProxy();
474 if (!virt_mem.tryReadString(path, pathname))
475 return -EFAULT;
476 if (!virt_mem.tryReadString(new_path, new_pathname))
477 return -EFAULT;
478
479 path = p->absolutePath(path, true);
480 new_path = p->absolutePath(new_path, true);
481
482 int result = link(path.c_str(), new_path.c_str());
483 return (result == -1) ? -errno : result;
484 }
485
486 SyscallReturn
487 symlinkFunc(SyscallDesc *desc, 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 = symlink(path.c_str(), new_path.c_str());
504 return (result == -1) ? -errno : result;
505 }
506
507 SyscallReturn
508 mkdirFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname, mode_t mode)
509 {
510 auto p = tc->getProcessPtr();
511 std::string path;
512 if (!tc->getVirtProxy().tryReadString(path, pathname))
513 return -EFAULT;
514
515 path = p->checkPathRedirect(path);
516
517 auto result = mkdir(path.c_str(), mode);
518 return (result == -1) ? -errno : result;
519 }
520
521 SyscallReturn
522 renameFunc(SyscallDesc *desc, ThreadContext *tc, Addr oldpath, Addr newpath)
523 {
524 auto p = tc->getProcessPtr();
525
526 string old_name;
527 if (!tc->getVirtProxy().tryReadString(old_name, oldpath))
528 return -EFAULT;
529
530 string new_name;
531 if (!tc->getVirtProxy().tryReadString(new_name, newpath))
532 return -EFAULT;
533
534 // Adjust path for cwd and redirection
535 old_name = p->checkPathRedirect(old_name);
536 new_name = p->checkPathRedirect(new_name);
537
538 int64_t result = rename(old_name.c_str(), new_name.c_str());
539 return (result == -1) ? -errno : result;
540 }
541
542 SyscallReturn
543 truncateFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname, off_t length)
544 {
545 string path;
546 auto p = tc->getProcessPtr();
547
548 if (!tc->getVirtProxy().tryReadString(path, pathname))
549 return -EFAULT;
550
551 // Adjust path for cwd and redirection
552 path = p->checkPathRedirect(path);
553
554 int result = truncate(path.c_str(), length);
555 return (result == -1) ? -errno : result;
556 }
557
558 SyscallReturn
559 ftruncateFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, off_t length)
560 {
561 auto p = tc->getProcessPtr();
562
563 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
564 if (!ffdp)
565 return -EBADF;
566 int sim_fd = ffdp->getSimFD();
567
568 int result = ftruncate(sim_fd, length);
569 return (result == -1) ? -errno : result;
570 }
571
572 SyscallReturn
573 truncate64Func(SyscallDesc *desc, ThreadContext *tc,
574 Addr pathname, int64_t length)
575 {
576 auto process = tc->getProcessPtr();
577 string path;
578
579 if (!tc->getVirtProxy().tryReadString(path, pathname))
580 return -EFAULT;
581
582 // Adjust path for cwd and redirection
583 path = process->checkPathRedirect(path);
584
585 #if NO_STAT64
586 int result = truncate(path.c_str(), length);
587 #else
588 int result = truncate64(path.c_str(), length);
589 #endif
590 return (result == -1) ? -errno : result;
591 }
592
593 SyscallReturn
594 ftruncate64Func(SyscallDesc *desc, ThreadContext *tc,
595 int tgt_fd, int64_t length)
596 {
597 auto p = tc->getProcessPtr();
598
599 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
600 if (!ffdp)
601 return -EBADF;
602 int sim_fd = ffdp->getSimFD();
603
604 #if NO_STAT64
605 int result = ftruncate(sim_fd, length);
606 #else
607 int result = ftruncate64(sim_fd, length);
608 #endif
609 return (result == -1) ? -errno : result;
610 }
611
612 SyscallReturn
613 umaskFunc(SyscallDesc *desc, ThreadContext *tc)
614 {
615 // Letting the simulated program change the simulator's umask seems like
616 // a bad idea. Compromise by just returning the current umask but not
617 // changing anything.
618 mode_t oldMask = umask(0);
619 umask(oldMask);
620 return (int)oldMask;
621 }
622
623 SyscallReturn
624 chownFunc(SyscallDesc *desc, ThreadContext *tc,
625 Addr pathname, uint32_t owner, uint32_t group)
626 {
627 string path;
628 auto p = tc->getProcessPtr();
629
630 if (!tc->getVirtProxy().tryReadString(path, pathname))
631 return -EFAULT;
632
633 /* XXX endianess */
634 uid_t hostOwner = owner;
635 gid_t hostGroup = group;
636
637 // Adjust path for cwd and redirection
638 path = p->checkPathRedirect(path);
639
640 int result = chown(path.c_str(), hostOwner, hostGroup);
641 return (result == -1) ? -errno : result;
642 }
643
644 SyscallReturn
645 fchownFunc(SyscallDesc *desc, ThreadContext *tc,
646 int tgt_fd, uint32_t owner, uint32_t group)
647 {
648 auto p = tc->getProcessPtr();
649
650 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
651 if (!ffdp)
652 return -EBADF;
653 int sim_fd = ffdp->getSimFD();
654
655 /* XXX endianess */
656 uid_t hostOwner = owner;
657 gid_t hostGroup = group;
658
659 int result = fchown(sim_fd, hostOwner, hostGroup);
660 return (result == -1) ? -errno : result;
661 }
662
663 /**
664 * FIXME: The file description is not shared among file descriptors created
665 * with dup. Really, it's difficult to maintain fields like file offset or
666 * flags since an update to such a field won't be reflected in the metadata
667 * for the fd entries that we maintain for checkpoint restoration.
668 */
669 SyscallReturn
670 dupFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd)
671 {
672 auto p = tc->getProcessPtr();
673
674 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
675 if (!old_hbfdp)
676 return -EBADF;
677 int sim_fd = old_hbfdp->getSimFD();
678
679 int result = dup(sim_fd);
680 if (result == -1)
681 return -errno;
682
683 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone());
684 new_hbfdp->setSimFD(result);
685 new_hbfdp->setCOE(false);
686 return p->fds->allocFD(new_hbfdp);
687 }
688
689 SyscallReturn
690 dup2Func(SyscallDesc *desc, ThreadContext *tc, int old_tgt_fd, int new_tgt_fd)
691 {
692 auto p = tc->getProcessPtr();
693 auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]);
694 if (!old_hbp)
695 return -EBADF;
696 int old_sim_fd = old_hbp->getSimFD();
697
698 /**
699 * We need a valid host file descriptor number to be able to pass into
700 * the second parameter for dup2 (newfd), but we don't know what the
701 * viable numbers are; we execute the open call to retrieve one.
702 */
703 int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY));
704 if (res_fd == -1)
705 return -errno;
706
707 auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]);
708 if (new_hbp)
709 p->fds->closeFDEntry(new_tgt_fd);
710 new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone());
711 new_hbp->setSimFD(res_fd);
712 new_hbp->setCOE(false);
713
714 return p->fds->allocFD(new_hbp);
715 }
716
717 SyscallReturn
718 fcntlFunc(SyscallDesc *desc, ThreadContext *tc,
719 int tgt_fd, int cmd, GuestABI::VarArgs<int> varargs)
720 {
721 auto p = tc->getProcessPtr();
722
723 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
724 if (!hbfdp)
725 return -EBADF;
726 int sim_fd = hbfdp->getSimFD();
727
728 int coe = hbfdp->getCOE();
729
730 switch (cmd) {
731 case F_GETFD:
732 return coe & FD_CLOEXEC;
733
734 case F_SETFD: {
735 int arg = varargs.get<int>();
736 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false);
737 return 0;
738 }
739
740 // Rely on the host to maintain the file status flags for this file
741 // description rather than maintain it ourselves. Admittedly, this
742 // is suboptimal (and possibly error prone), but it is difficult to
743 // maintain the flags by tracking them across the different descriptors
744 // (that refer to this file description) caused by clone, dup, and
745 // subsequent fcntls.
746 case F_GETFL:
747 case F_SETFL: {
748 int arg = varargs.get<int>();
749 int rv = fcntl(sim_fd, cmd, arg);
750 return (rv == -1) ? -errno : rv;
751 }
752
753 default:
754 warn("fcntl: unsupported command %d\n", cmd);
755 return 0;
756 }
757 }
758
759 SyscallReturn
760 fcntl64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int cmd)
761 {
762 auto p = tc->getProcessPtr();
763
764 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
765 if (!hbfdp)
766 return -EBADF;
767 int sim_fd = hbfdp->getSimFD();
768
769 switch (cmd) {
770 case 33: //F_GETLK64
771 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
772 return -EMFILE;
773
774 case 34: // F_SETLK64
775 case 35: // F_SETLKW64
776 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
777 tgt_fd);
778 return -EMFILE;
779
780 default:
781 // not sure if this is totally valid, but we'll pass it through
782 // to the underlying OS
783 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd);
784 return fcntl(sim_fd, cmd);
785 }
786 }
787
788 SyscallReturn
789 pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc)
790 {
791 return pipe2Func(desc, tc, 0, 0);
792 }
793
794 SyscallReturn
795 pipeFunc(SyscallDesc *desc, ThreadContext *tc, Addr tgt_addr)
796 {
797 return pipe2Func(desc, tc, tgt_addr, 0);
798 }
799
800 SyscallReturn
801 pipe2Func(SyscallDesc *desc, ThreadContext *tc, Addr tgt_addr, int flags)
802 {
803 auto p = tc->getProcessPtr();
804
805 int sim_fds[2], tgt_fds[2];
806
807 int pipe_retval = pipe(sim_fds);
808 if (pipe_retval == -1)
809 return -errno;
810
811 auto rend = PipeFDEntry::EndType::read;
812 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
813 tgt_fds[0] = p->fds->allocFD(rpfd);
814 int sim_fd_rpfd = rpfd->getSimFD();
815
816 auto wend = PipeFDEntry::EndType::write;
817 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
818 tgt_fds[1] = p->fds->allocFD(wpfd);
819 int sim_fd_wpfd = wpfd->getSimFD();
820
821 /**
822 * Now patch the read object to record the target file descriptor chosen
823 * as the write end of the pipe.
824 */
825 rpfd->setPipeReadSource(tgt_fds[1]);
826
827 /**
828 * On some architectures, it's possible to use more than one register for
829 * a return value. In those cases, pipe returns its values rather than
830 * write them into a buffer.
831 */
832 if (tgt_addr == 0)
833 return SyscallReturn(tgt_fds[0], tgt_fds[1]);
834
835 /**
836 * Copy the target file descriptors into buffer space and then copy
837 * the buffer space back into the target address space.
838 */
839 BufferArg tgt_handle(tgt_addr, sizeof(int[2]));
840 int *buf_ptr = (int*)tgt_handle.bufferPtr();
841 buf_ptr[0] = tgt_fds[0];
842 buf_ptr[1] = tgt_fds[1];
843 tgt_handle.copyOut(tc->getVirtProxy());
844
845 if (flags) {
846 // pipe2 only uses O_NONBLOCK, O_CLOEXEC, and (O_NONBLOCK | O_CLOEXEC)
847 // if flags set to anything else, return EINVAL
848 if ((flags != O_CLOEXEC) && (flags != O_NONBLOCK) &&
849 (flags != (O_CLOEXEC | O_NONBLOCK))) {
850 return -EINVAL;
851 }
852
853 /*
854 If O_NONBLOCK is passed in as a flag to pipe2, set O_NONBLOCK file
855 status flag for two new open file descriptors.
856 */
857 if (flags & O_NONBLOCK) {
858 /*
859 O_NONBLOCK is set when the programmer wants to avoid a separate
860 call(s) to fcntl in their code, so mirror the fcntl
861 implementation for handling file descriptors -- rely on host to
862 maintain file status flags.
863 */
864 if (fcntl(sim_fd_rpfd, F_SETFL, O_NONBLOCK)) {
865 return -errno;
866 }
867 if (fcntl(sim_fd_wpfd, F_SETFL, O_NONBLOCK)) {
868 return -errno;
869 }
870 }
871
872 /*
873 If O_CLOEXEC is passed in as a flag to pipe2, set close-on-exec
874 (FD_CLOEXEC) file status flag for two new open file descriptors.
875 */
876 if (flags & O_CLOEXEC) {
877 rpfd->setCOE(true);
878 wpfd->setCOE(true);
879 }
880 }
881
882 return 0;
883 }
884
885 SyscallReturn
886 getpgrpFunc(SyscallDesc *desc, ThreadContext *tc)
887 {
888 auto process = tc->getProcessPtr();
889 return process->pgid();
890 }
891
892 SyscallReturn
893 setpgidFunc(SyscallDesc *desc, ThreadContext *tc, int pid, int pgid)
894 {
895 auto process = tc->getProcessPtr();
896
897 if (pgid < 0)
898 return -EINVAL;
899
900 if (pid == 0) {
901 process->pgid(process->pid());
902 return 0;
903 }
904
905 Process *matched_ph = nullptr;
906 System *sysh = tc->getSystemPtr();
907
908 // Retrieves process pointer from active/suspended thread contexts.
909 for (auto *tc: sysh->threads) {
910 if (tc->status() != ThreadContext::Halted) {
911 Process *temp_h = tc->getProcessPtr();
912 Process *walk_ph = (Process*)temp_h;
913
914 if (walk_ph && walk_ph->pid() == process->pid())
915 matched_ph = walk_ph;
916 }
917 }
918
919 assert(matched_ph);
920 matched_ph->pgid((pgid == 0) ? matched_ph->pid() : pgid);
921
922 return 0;
923 }
924
925
926 SyscallReturn
927 getpidFunc(SyscallDesc *desc, ThreadContext *tc)
928 {
929 auto process = tc->getProcessPtr();
930 return process->tgid();
931 }
932
933 SyscallReturn
934 gettidFunc(SyscallDesc *desc, ThreadContext *tc)
935 {
936 auto process = tc->getProcessPtr();
937 return process->pid();
938 }
939
940 SyscallReturn
941 getppidFunc(SyscallDesc *desc, ThreadContext *tc)
942 {
943 auto process = tc->getProcessPtr();
944 return process->ppid();
945 }
946
947 SyscallReturn
948 getuidFunc(SyscallDesc *desc, ThreadContext *tc)
949 {
950 auto process = tc->getProcessPtr();
951 return process->uid(); // UID
952 }
953
954 SyscallReturn
955 geteuidFunc(SyscallDesc *desc, ThreadContext *tc)
956 {
957 auto process = tc->getProcessPtr();
958 return process->euid(); // UID
959 }
960
961 SyscallReturn
962 getgidFunc(SyscallDesc *desc, ThreadContext *tc)
963 {
964 auto process = tc->getProcessPtr();
965 return process->gid();
966 }
967
968 SyscallReturn
969 getegidFunc(SyscallDesc *desc, ThreadContext *tc)
970 {
971 auto process = tc->getProcessPtr();
972 return process->egid();
973 }
974
975 SyscallReturn
976 fallocateFunc(SyscallDesc *desc, ThreadContext *tc,
977 int tgt_fd, int mode, off_t offset, off_t len)
978 {
979 #if defined(__linux__)
980 auto p = tc->getProcessPtr();
981
982 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
983 if (!ffdp)
984 return -EBADF;
985 int sim_fd = ffdp->getSimFD();
986
987 int result = fallocate(sim_fd, mode, offset, len);
988 if (result < 0)
989 return -errno;
990 return 0;
991 #else
992 warnUnsupportedOS("fallocate");
993 return -1;
994 #endif
995 }
996
997 SyscallReturn
998 accessFunc(SyscallDesc *desc, ThreadContext *tc,
999 Addr pathname, mode_t mode)
1000 {
1001 string path;
1002 auto p = tc->getProcessPtr();
1003 if (!tc->getVirtProxy().tryReadString(path, pathname))
1004 return -EFAULT;
1005
1006 // Adjust path for cwd and redirection
1007 path = p->checkPathRedirect(path);
1008
1009 int result = access(path.c_str(), mode);
1010 return (result == -1) ? -errno : result;
1011 }
1012
1013 SyscallReturn
1014 mknodFunc(SyscallDesc *desc, ThreadContext *tc,
1015 Addr pathname, mode_t mode, dev_t dev)
1016 {
1017 auto p = tc->getProcessPtr();
1018 std::string path;
1019 if (!tc->getVirtProxy().tryReadString(path, pathname))
1020 return -EFAULT;
1021
1022 path = p->checkPathRedirect(path);
1023
1024 auto result = mknod(path.c_str(), mode, dev);
1025 return (result == -1) ? -errno : result;
1026 }
1027
1028 SyscallReturn
1029 chdirFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname)
1030 {
1031 auto p = tc->getProcessPtr();
1032 std::string path;
1033 if (!tc->getVirtProxy().tryReadString(path, pathname))
1034 return -EFAULT;
1035
1036 std::string tgt_cwd;
1037 if (startswith(path, "/")) {
1038 tgt_cwd = path;
1039 } else {
1040 char buf[PATH_MAX];
1041 tgt_cwd = realpath((p->tgtCwd + "/" + path).c_str(), buf);
1042 }
1043 std::string host_cwd = p->checkPathRedirect(tgt_cwd);
1044
1045 int result = chdir(host_cwd.c_str());
1046
1047 if (result == -1)
1048 return -errno;
1049
1050 p->hostCwd = host_cwd;
1051 p->tgtCwd = tgt_cwd;
1052 return result;
1053 }
1054
1055 SyscallReturn
1056 rmdirFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname)
1057 {
1058 auto p = tc->getProcessPtr();
1059 std::string path;
1060 if (!tc->getVirtProxy().tryReadString(path, pathname))
1061 return -EFAULT;
1062
1063 path = p->checkPathRedirect(path);
1064
1065 auto result = rmdir(path.c_str());
1066 return (result == -1) ? -errno : result;
1067 }
1068
1069 #if defined(SYS_getdents) || defined(SYS_getdents64)
1070 template<typename DE, int SYS_NUM>
1071 static SyscallReturn
1072 getdentsImpl(SyscallDesc *desc, ThreadContext *tc,
1073 int tgt_fd, Addr buf_ptr, unsigned count)
1074 {
1075 auto p = tc->getProcessPtr();
1076
1077 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1078 if (!hbfdp)
1079 return -EBADF;
1080 int sim_fd = hbfdp->getSimFD();
1081
1082 BufferArg buf_arg(buf_ptr, count);
1083 auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count);
1084
1085 if (status == -1)
1086 return -errno;
1087
1088 unsigned traversed = 0;
1089 while (traversed < status) {
1090 DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed);
1091
1092 auto host_reclen = buffer->d_reclen;
1093
1094 /**
1095 * Convert the byte ordering from the host to the target before
1096 * passing the data back into the target's address space to preserve
1097 * endianness.
1098 */
1099 const ByteOrder bo = tc->getSystemPtr()->getGuestByteOrder();
1100 buffer->d_ino = htog(buffer->d_ino, bo);
1101 buffer->d_off = htog(buffer->d_off, bo);
1102 buffer->d_reclen = htog(buffer->d_reclen, bo);
1103
1104 traversed += host_reclen;
1105 }
1106
1107 buf_arg.copyOut(tc->getVirtProxy());
1108 return status;
1109 }
1110 #endif
1111
1112 #if defined(SYS_getdents)
1113 SyscallReturn
1114 getdentsFunc(SyscallDesc *desc, ThreadContext *tc,
1115 int tgt_fd, Addr buf_ptr, unsigned count)
1116 {
1117 typedef struct linux_dirent {
1118 unsigned long d_ino;
1119 unsigned long d_off;
1120 unsigned short d_reclen;
1121 char dname[];
1122 } LinDent;
1123
1124 return getdentsImpl<LinDent, SYS_getdents>(desc, tc,
1125 tgt_fd, buf_ptr, count);
1126 }
1127 #endif
1128
1129 #if defined(SYS_getdents64)
1130 SyscallReturn
1131 getdents64Func(SyscallDesc *desc, ThreadContext *tc,
1132 int tgt_fd, Addr buf_ptr, unsigned count)
1133 {
1134 typedef struct linux_dirent64 {
1135 ino64_t d_ino;
1136 off64_t d_off;
1137 unsigned short d_reclen;
1138 char dname[];
1139 } LinDent64;
1140
1141 return getdentsImpl<LinDent64, SYS_getdents64>(desc, tc,
1142 tgt_fd, buf_ptr, count);
1143 }
1144 #endif
1145
1146 SyscallReturn
1147 shutdownFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int how)
1148 {
1149 auto p = tc->getProcessPtr();
1150
1151 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1152 if (!sfdp)
1153 return -EBADF;
1154 int sim_fd = sfdp->getSimFD();
1155
1156 int retval = shutdown(sim_fd, how);
1157
1158 return (retval == -1) ? -errno : retval;
1159 }
1160
1161 SyscallReturn
1162 bindFunc(SyscallDesc *desc, ThreadContext *tc,
1163 int tgt_fd, Addr buf_ptr, int addrlen)
1164 {
1165 auto p = tc->getProcessPtr();
1166
1167 BufferArg bufSock(buf_ptr, addrlen);
1168 bufSock.copyIn(tc->getVirtProxy());
1169
1170 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1171 if (!sfdp)
1172 return -EBADF;
1173 int sim_fd = sfdp->getSimFD();
1174
1175 int status = ::bind(sim_fd,
1176 (struct sockaddr *)bufSock.bufferPtr(),
1177 addrlen);
1178
1179 return (status == -1) ? -errno : status;
1180 }
1181
1182 SyscallReturn
1183 listenFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int backlog)
1184 {
1185 auto p = tc->getProcessPtr();
1186
1187 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1188 if (!sfdp)
1189 return -EBADF;
1190 int sim_fd = sfdp->getSimFD();
1191
1192 int status = listen(sim_fd, backlog);
1193
1194 return (status == -1) ? -errno : status;
1195 }
1196
1197 SyscallReturn
1198 connectFunc(SyscallDesc *desc, ThreadContext *tc,
1199 int tgt_fd, Addr buf_ptr, int addrlen)
1200 {
1201 auto p = tc->getProcessPtr();
1202
1203 BufferArg addr(buf_ptr, addrlen);
1204 addr.copyIn(tc->getVirtProxy());
1205
1206 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1207 if (!sfdp)
1208 return -EBADF;
1209 int sim_fd = sfdp->getSimFD();
1210
1211 int status = connect(sim_fd,
1212 (struct sockaddr *)addr.bufferPtr(),
1213 (socklen_t)addrlen);
1214
1215 return (status == -1) ? -errno : status;
1216 }
1217
1218 SyscallReturn
1219 recvfromFunc(SyscallDesc *desc, ThreadContext *tc,
1220 int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags,
1221 Addr addrPtr, Addr addrlenPtr)
1222 {
1223 auto p = tc->getProcessPtr();
1224
1225 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1226 if (!sfdp)
1227 return -EBADF;
1228 int sim_fd = sfdp->getSimFD();
1229
1230 // Reserve buffer space.
1231 BufferArg bufrBuf(bufrPtr, bufrLen);
1232
1233 // Get address length.
1234 socklen_t addrLen = 0;
1235 if (addrlenPtr != 0) {
1236 // Read address length parameter.
1237 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1238 addrlenBuf.copyIn(tc->getVirtProxy());
1239 addrLen = *((socklen_t *)addrlenBuf.bufferPtr());
1240 }
1241
1242 struct sockaddr sa, *sap = NULL;
1243 if (addrLen != 0) {
1244 BufferArg addrBuf(addrPtr, addrLen);
1245 addrBuf.copyIn(tc->getVirtProxy());
1246 memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(),
1247 sizeof(struct sockaddr));
1248 sap = &sa;
1249 }
1250
1251 ssize_t recvd_size = recvfrom(sim_fd,
1252 (void *)bufrBuf.bufferPtr(),
1253 bufrLen, flags, sap, (socklen_t *)&addrLen);
1254
1255 if (recvd_size == -1)
1256 return -errno;
1257
1258 // Pass the received data out.
1259 bufrBuf.copyOut(tc->getVirtProxy());
1260
1261 // Copy address to addrPtr and pass it on.
1262 if (sap != NULL) {
1263 BufferArg addrBuf(addrPtr, addrLen);
1264 memcpy(addrBuf.bufferPtr(), sap, sizeof(sa));
1265 addrBuf.copyOut(tc->getVirtProxy());
1266 }
1267
1268 // Copy len to addrlenPtr and pass it on.
1269 if (addrLen != 0) {
1270 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1271 *(socklen_t *)addrlenBuf.bufferPtr() = addrLen;
1272 addrlenBuf.copyOut(tc->getVirtProxy());
1273 }
1274
1275 return recvd_size;
1276 }
1277
1278 SyscallReturn
1279 sendtoFunc(SyscallDesc *desc, ThreadContext *tc,
1280 int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags,
1281 Addr addrPtr, socklen_t addrLen)
1282 {
1283 auto p = tc->getProcessPtr();
1284
1285 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1286 if (!sfdp)
1287 return -EBADF;
1288 int sim_fd = sfdp->getSimFD();
1289
1290 // Reserve buffer space.
1291 BufferArg bufrBuf(bufrPtr, bufrLen);
1292 bufrBuf.copyIn(tc->getVirtProxy());
1293
1294 struct sockaddr sa, *sap = nullptr;
1295 memset(&sa, 0, sizeof(sockaddr));
1296 if (addrLen != 0) {
1297 BufferArg addrBuf(addrPtr, addrLen);
1298 addrBuf.copyIn(tc->getVirtProxy());
1299 memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen);
1300 sap = &sa;
1301 }
1302
1303 ssize_t sent_size = sendto(sim_fd,
1304 (void *)bufrBuf.bufferPtr(),
1305 bufrLen, flags, sap, (socklen_t)addrLen);
1306
1307 return (sent_size == -1) ? -errno : sent_size;
1308 }
1309
1310 SyscallReturn
1311 recvmsgFunc(SyscallDesc *desc, ThreadContext *tc,
1312 int tgt_fd, Addr msgPtr, int flags)
1313 {
1314 auto p = tc->getProcessPtr();
1315
1316 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1317 if (!sfdp)
1318 return -EBADF;
1319 int sim_fd = sfdp->getSimFD();
1320
1321 /**
1322 * struct msghdr {
1323 * void *msg_name; // optional address
1324 * socklen_t msg_namelen; // size of address
1325 * struct iovec *msg_iov; // iovec array
1326 * size_t msg_iovlen; // number entries in msg_iov
1327 * i // entries correspond to buffer
1328 * void *msg_control; // ancillary data
1329 * size_t msg_controllen; // ancillary data buffer len
1330 * int msg_flags; // flags on received message
1331 * };
1332 *
1333 * struct iovec {
1334 * void *iov_base; // starting address
1335 * size_t iov_len; // number of bytes to transfer
1336 * };
1337 */
1338
1339 /**
1340 * The plan with this system call is to replace all of the pointers in the
1341 * structure and the substructure with BufferArg class pointers. We will
1342 * copy every field from the structures into our BufferArg classes.
1343 */
1344 BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1345 msgBuf.copyIn(tc->getVirtProxy());
1346 struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr();
1347
1348 /**
1349 * We will use these address place holders to retain the pointers which
1350 * we are going to replace with our own buffers in our simulator address
1351 * space.
1352 */
1353 Addr msg_name_phold = 0;
1354 Addr msg_iov_phold = 0;
1355 Addr iovec_base_phold[msgHdr->msg_iovlen];
1356 Addr msg_control_phold = 0;
1357
1358 /**
1359 * Record msg_name pointer then replace with buffer pointer.
1360 */
1361 BufferArg *nameBuf = NULL;
1362 if (msgHdr->msg_name) {
1363 /*1*/msg_name_phold = (Addr)msgHdr->msg_name;
1364 /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen);
1365 /*3*/nameBuf->copyIn(tc->getVirtProxy());
1366 /*4*/msgHdr->msg_name = nameBuf->bufferPtr();
1367 }
1368
1369 /**
1370 * Record msg_iov pointer then replace with buffer pointer. Also, setup
1371 * an array of buffer pointers for the iovec structs record and replace
1372 * their pointers with buffer pointers.
1373 */
1374 BufferArg *iovBuf = NULL;
1375 BufferArg *iovecBuf[msgHdr->msg_iovlen];
1376 for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1377 iovec_base_phold[i] = 0;
1378 iovecBuf[i] = NULL;
1379 }
1380
1381 if (msgHdr->msg_iov) {
1382 /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov;
1383 /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen *
1384 sizeof(struct iovec));
1385 /*3*/iovBuf->copyIn(tc->getVirtProxy());
1386 for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1387 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1388 /*1*/iovec_base_phold[i] =
1389 (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base;
1390 /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i],
1391 ((struct iovec *)iovBuf->bufferPtr())[i].iov_len);
1392 /*3*/iovecBuf[i]->copyIn(tc->getVirtProxy());
1393 /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1394 iovecBuf[i]->bufferPtr();
1395 }
1396 }
1397 /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr();
1398 }
1399
1400 /**
1401 * Record msg_control pointer then replace with buffer pointer.
1402 */
1403 BufferArg *controlBuf = NULL;
1404 if (msgHdr->msg_control) {
1405 /*1*/msg_control_phold = (Addr)msgHdr->msg_control;
1406 /*2*/controlBuf = new BufferArg(msg_control_phold,
1407 CMSG_ALIGN(msgHdr->msg_controllen));
1408 /*3*/controlBuf->copyIn(tc->getVirtProxy());
1409 /*4*/msgHdr->msg_control = controlBuf->bufferPtr();
1410 }
1411
1412 ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags);
1413
1414 if (recvd_size < 0)
1415 return -errno;
1416
1417 if (msgHdr->msg_name) {
1418 nameBuf->copyOut(tc->getVirtProxy());
1419 delete(nameBuf);
1420 msgHdr->msg_name = (void *)msg_name_phold;
1421 }
1422
1423 if (msgHdr->msg_iov) {
1424 for (int i = 0; i< msgHdr->msg_iovlen; i++) {
1425 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1426 iovecBuf[i]->copyOut(tc->getVirtProxy());
1427 delete iovecBuf[i];
1428 ((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1429 (void *)iovec_base_phold[i];
1430 }
1431 }
1432 iovBuf->copyOut(tc->getVirtProxy());
1433 delete iovBuf;
1434 msgHdr->msg_iov = (struct iovec *)msg_iov_phold;
1435 }
1436
1437 if (msgHdr->msg_control) {
1438 controlBuf->copyOut(tc->getVirtProxy());
1439 delete(controlBuf);
1440 msgHdr->msg_control = (void *)msg_control_phold;
1441 }
1442
1443 msgBuf.copyOut(tc->getVirtProxy());
1444
1445 return recvd_size;
1446 }
1447
1448 SyscallReturn
1449 sendmsgFunc(SyscallDesc *desc, ThreadContext *tc,
1450 int tgt_fd, Addr msgPtr, int flags)
1451 {
1452 auto p = tc->getProcessPtr();
1453
1454 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1455 if (!sfdp)
1456 return -EBADF;
1457 int sim_fd = sfdp->getSimFD();
1458
1459 /**
1460 * Reserve buffer space.
1461 */
1462 BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1463 msgBuf.copyIn(tc->getVirtProxy());
1464 struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr());
1465
1466 /**
1467 * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
1468 * recvmsg without a buffer.
1469 */
1470 struct iovec *iovPtr = msgHdr.msg_iov;
1471 BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen);
1472 iovBuf.copyIn(tc->getVirtProxy());
1473 struct iovec *iov = (struct iovec *)iovBuf.bufferPtr();
1474 msgHdr.msg_iov = iov;
1475
1476 /**
1477 * Cannot instantiate buffers till inside the loop.
1478 * Create array to hold buffer addresses, to be used during copyIn of
1479 * send data.
1480 */
1481 BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen
1482 * sizeof(BufferArg *));
1483
1484 /**
1485 * Iterate through the iovec structures:
1486 * Get the base buffer addreses, reserve iov_len amount of space for each.
1487 * Put the buf address into the bufferArray for later retrieval.
1488 */
1489 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1490 Addr basePtr = (Addr) iov[iovIndex].iov_base;
1491 bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len);
1492 bufferArray[iovIndex]->copyIn(tc->getVirtProxy());
1493 iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr();
1494 }
1495
1496 ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags);
1497 int local_errno = errno;
1498
1499 /**
1500 * Free dynamically allocated memory.
1501 */
1502 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1503 BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex];
1504 delete(baseBuf);
1505 }
1506
1507 /**
1508 * Malloced above.
1509 */
1510 free(bufferArray);
1511
1512 return (sent_size < 0) ? -local_errno : sent_size;
1513 }
1514
1515 SyscallReturn
1516 getsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
1517 int tgt_fd, int level, int optname, Addr valPtr, Addr lenPtr)
1518 {
1519 // union of all possible return value types from getsockopt
1520 union val {
1521 int i_val;
1522 long l_val;
1523 struct linger linger_val;
1524 struct timeval timeval_val;
1525 } val;
1526
1527 auto p = tc->getProcessPtr();
1528
1529 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1530 if (!sfdp)
1531 return -EBADF;
1532 int sim_fd = sfdp->getSimFD();
1533
1534 socklen_t len = sizeof(val);
1535 int status = getsockopt(sim_fd, level, optname, &val, &len);
1536
1537 if (status == -1)
1538 return -errno;
1539
1540 // copy val to valPtr and pass it on
1541 BufferArg valBuf(valPtr, sizeof(val));
1542 memcpy(valBuf.bufferPtr(), &val, sizeof(val));
1543 valBuf.copyOut(tc->getVirtProxy());
1544
1545 // copy len to lenPtr and pass it on
1546 BufferArg lenBuf(lenPtr, sizeof(len));
1547 memcpy(lenBuf.bufferPtr(), &len, sizeof(len));
1548 lenBuf.copyOut(tc->getVirtProxy());
1549
1550 return status;
1551 }
1552
1553 SyscallReturn
1554 getsocknameFunc(SyscallDesc *desc, ThreadContext *tc,
1555 int tgt_fd, Addr addrPtr, Addr lenPtr)
1556 {
1557 auto p = tc->getProcessPtr();
1558
1559 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1560 if (!sfdp)
1561 return -EBADF;
1562 int sim_fd = sfdp->getSimFD();
1563
1564 // lenPtr is an in-out paramenter:
1565 // sending the address length in, conveying the final length out
1566
1567 // Read in the value of len from the passed pointer.
1568 BufferArg lenBuf(lenPtr, sizeof(socklen_t));
1569 lenBuf.copyIn(tc->getVirtProxy());
1570 socklen_t len = *(socklen_t *)lenBuf.bufferPtr();
1571
1572 struct sockaddr sa;
1573 int status = getsockname(sim_fd, &sa, &len);
1574
1575 if (status == -1)
1576 return -errno;
1577
1578 // Copy address to addrPtr and pass it on.
1579 BufferArg addrBuf(addrPtr, sizeof(sa));
1580 memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa));
1581 addrBuf.copyOut(tc->getVirtProxy());
1582
1583 // Copy len to lenPtr and pass it on.
1584 *(socklen_t *)lenBuf.bufferPtr() = len;
1585 lenBuf.copyOut(tc->getVirtProxy());
1586
1587 return status;
1588 }
1589
1590 SyscallReturn
1591 getpeernameFunc(SyscallDesc *desc, ThreadContext *tc,
1592 int tgt_fd, Addr sockAddrPtr, Addr addrlenPtr)
1593 {
1594 auto p = tc->getProcessPtr();
1595
1596 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1597 if (!sfdp)
1598 return -EBADF;
1599 int sim_fd = sfdp->getSimFD();
1600
1601 BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned));
1602 bufAddrlen.copyIn(tc->getVirtProxy());
1603 BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr());
1604
1605 int retval = getpeername(sim_fd,
1606 (struct sockaddr *)bufSock.bufferPtr(),
1607 (unsigned *)bufAddrlen.bufferPtr());
1608
1609 if (retval != -1) {
1610 bufSock.copyOut(tc->getVirtProxy());
1611 bufAddrlen.copyOut(tc->getVirtProxy());
1612 }
1613
1614 return (retval == -1) ? -errno : retval;
1615 }
1616
1617 SyscallReturn
1618 setsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
1619 int tgt_fd, int level, int optname, Addr valPtr, socklen_t len)
1620 {
1621 auto p = tc->getProcessPtr();
1622
1623 BufferArg valBuf(valPtr, len);
1624 valBuf.copyIn(tc->getVirtProxy());
1625
1626 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1627 if (!sfdp)
1628 return -EBADF;
1629 int sim_fd = sfdp->getSimFD();
1630
1631 int status = setsockopt(sim_fd, level, optname,
1632 (struct sockaddr *)valBuf.bufferPtr(), len);
1633
1634 return (status == -1) ? -errno : status;
1635 }
1636
1637 SyscallReturn
1638 getcpuFunc(SyscallDesc *desc, ThreadContext *tc,
1639 Addr cpu_ptr, Addr node_ptr, Addr tcache_ptr)
1640 {
1641 bool error = false;
1642
1643 // unsigned is the same size (4) on all Linux supported ISAs.
1644 if (cpu_ptr != 0) {
1645 TypedBufferArg<uint32_t> result(cpu_ptr);
1646 *result = htog(tc->contextId(),
1647 tc->getSystemPtr()->getGuestByteOrder());
1648 error |= !result.copyOut(tc->getVirtProxy());
1649 }
1650
1651 // Set a fixed NUMA node 0.
1652 if (node_ptr != 0) {
1653 TypedBufferArg<uint32_t> result(node_ptr);
1654 *result = 0;
1655 error |= !result.copyOut(tc->getVirtProxy());
1656 }
1657
1658 return error ? -EFAULT : 0;
1659 }