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