syscall_emul.cc revision 14020:c9bf7a011602
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->getMemProxy());
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->getMemProxy();
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->getMemProxy());
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->getMemProxy());
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->getMemProxy());
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->getMemProxy().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->getMemProxy());
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->getMemProxy().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->getMemProxy();
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->getMemProxy();
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->getMemProxy().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->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index)))
575        return -EFAULT;
576
577    string new_name;
578
579    if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index)))
580        return -EFAULT;
581
582    // Adjust path for cwd and redirection
583    old_name = p->checkPathRedirect(old_name);
584    new_name = p->checkPathRedirect(new_name);
585
586    int64_t result = rename(old_name.c_str(), new_name.c_str());
587    return (result == -1) ? -errno : result;
588}
589
590SyscallReturn
591truncateFunc(SyscallDesc *desc, int num, ThreadContext *tc)
592{
593    string path;
594    auto p = tc->getProcessPtr();
595
596    int index = 0;
597    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
598        return -EFAULT;
599
600    off_t length = p->getSyscallArg(tc, index);
601
602    // Adjust path for cwd and redirection
603    path = p->checkPathRedirect(path);
604
605    int result = truncate(path.c_str(), length);
606    return (result == -1) ? -errno : result;
607}
608
609SyscallReturn
610ftruncateFunc(SyscallDesc *desc, int num, ThreadContext *tc)
611{
612    int index = 0;
613    auto p = tc->getProcessPtr();
614    int tgt_fd = p->getSyscallArg(tc, index);
615    off_t length = p->getSyscallArg(tc, index);
616
617    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
618    if (!ffdp)
619        return -EBADF;
620    int sim_fd = ffdp->getSimFD();
621
622    int result = ftruncate(sim_fd, length);
623    return (result == -1) ? -errno : result;
624}
625
626SyscallReturn
627truncate64Func(SyscallDesc *desc, int num, ThreadContext *tc)
628{
629    int index = 0;
630    auto process = tc->getProcessPtr();
631    string path;
632
633    if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index)))
634        return -EFAULT;
635
636    int64_t length = process->getSyscallArg(tc, index, 64);
637
638    // Adjust path for cwd and redirection
639    path = process->checkPathRedirect(path);
640
641#if NO_STAT64
642    int result = truncate(path.c_str(), length);
643#else
644    int result = truncate64(path.c_str(), length);
645#endif
646    return (result == -1) ? -errno : result;
647}
648
649SyscallReturn
650ftruncate64Func(SyscallDesc *desc, int num, ThreadContext *tc)
651{
652    int index = 0;
653    auto p = tc->getProcessPtr();
654    int tgt_fd = p->getSyscallArg(tc, index);
655    int64_t length = p->getSyscallArg(tc, index, 64);
656
657    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
658    if (!ffdp)
659        return -EBADF;
660    int sim_fd = ffdp->getSimFD();
661
662#if NO_STAT64
663    int result = ftruncate(sim_fd, length);
664#else
665    int result = ftruncate64(sim_fd, length);
666#endif
667    return (result == -1) ? -errno : result;
668}
669
670SyscallReturn
671umaskFunc(SyscallDesc *desc, int num, ThreadContext *tc)
672{
673    // Letting the simulated program change the simulator's umask seems like
674    // a bad idea.  Compromise by just returning the current umask but not
675    // changing anything.
676    mode_t oldMask = umask(0);
677    umask(oldMask);
678    return (int)oldMask;
679}
680
681SyscallReturn
682chownFunc(SyscallDesc *desc, int num, ThreadContext *tc)
683{
684    string path;
685    auto p = tc->getProcessPtr();
686
687    int index = 0;
688    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
689        return -EFAULT;
690
691    /* XXX endianess */
692    uint32_t owner = p->getSyscallArg(tc, index);
693    uid_t hostOwner = owner;
694    uint32_t group = p->getSyscallArg(tc, index);
695    gid_t hostGroup = group;
696
697    // Adjust path for cwd and redirection
698    path = p->checkPathRedirect(path);
699
700    int result = chown(path.c_str(), hostOwner, hostGroup);
701    return (result == -1) ? -errno : result;
702}
703
704SyscallReturn
705fchownFunc(SyscallDesc *desc, int num, ThreadContext *tc)
706{
707    int index = 0;
708    auto p = tc->getProcessPtr();
709    int tgt_fd = p->getSyscallArg(tc, index);
710
711    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
712    if (!ffdp)
713        return -EBADF;
714    int sim_fd = ffdp->getSimFD();
715
716    /* XXX endianess */
717    uint32_t owner = p->getSyscallArg(tc, index);
718    uid_t hostOwner = owner;
719    uint32_t group = p->getSyscallArg(tc, index);
720    gid_t hostGroup = group;
721
722    int result = fchown(sim_fd, hostOwner, hostGroup);
723    return (result == -1) ? -errno : result;
724}
725
726/**
727 * FIXME: The file description is not shared among file descriptors created
728 * with dup. Really, it's difficult to maintain fields like file offset or
729 * flags since an update to such a field won't be reflected in the metadata
730 * for the fd entries that we maintain for checkpoint restoration.
731 */
732SyscallReturn
733dupFunc(SyscallDesc *desc, int num, ThreadContext *tc)
734{
735    int index = 0;
736    auto p = tc->getProcessPtr();
737    int tgt_fd = p->getSyscallArg(tc, index);
738
739    auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
740    if (!old_hbfdp)
741        return -EBADF;
742    int sim_fd = old_hbfdp->getSimFD();
743
744    int result = dup(sim_fd);
745    if (result == -1)
746        return -errno;
747
748    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone());
749    new_hbfdp->setSimFD(result);
750    new_hbfdp->setCOE(false);
751    return p->fds->allocFD(new_hbfdp);
752}
753
754SyscallReturn
755dup2Func(SyscallDesc *desc, int num, ThreadContext *tc)
756{
757    int index = 0;
758    auto p = tc->getProcessPtr();
759    int old_tgt_fd = p->getSyscallArg(tc, index);
760    auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]);
761    if (!old_hbp)
762        return -EBADF;
763    int old_sim_fd = old_hbp->getSimFD();
764
765    /**
766     * We need a valid host file descriptor number to be able to pass into
767     * the second parameter for dup2 (newfd), but we don't know what the
768     * viable numbers are; we execute the open call to retrieve one.
769     */
770    int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY));
771    if (res_fd == -1)
772        return -errno;
773
774    int new_tgt_fd = p->getSyscallArg(tc, index);
775    auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]);
776    if (new_hbp)
777        p->fds->closeFDEntry(new_tgt_fd);
778    new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone());
779    new_hbp->setSimFD(res_fd);
780    new_hbp->setCOE(false);
781
782    return p->fds->allocFD(new_hbp);
783}
784
785SyscallReturn
786fcntlFunc(SyscallDesc *desc, int num, ThreadContext *tc)
787{
788    int arg;
789    int index = 0;
790    auto p = tc->getProcessPtr();
791    int tgt_fd = p->getSyscallArg(tc, index);
792    int cmd = p->getSyscallArg(tc, index);
793
794    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
795    if (!hbfdp)
796        return -EBADF;
797    int sim_fd = hbfdp->getSimFD();
798
799    int coe = hbfdp->getCOE();
800
801    switch (cmd) {
802      case F_GETFD:
803        return coe & FD_CLOEXEC;
804
805      case F_SETFD: {
806        arg = p->getSyscallArg(tc, index);
807        arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false);
808        return 0;
809      }
810
811      // Rely on the host to maintain the file status flags for this file
812      // description rather than maintain it ourselves. Admittedly, this
813      // is suboptimal (and possibly error prone), but it is difficult to
814      // maintain the flags by tracking them across the different descriptors
815      // (that refer to this file description) caused by clone, dup, and
816      // subsequent fcntls.
817      case F_GETFL:
818      case F_SETFL: {
819        arg = p->getSyscallArg(tc, index);
820        int rv = fcntl(sim_fd, cmd, arg);
821        return (rv == -1) ? -errno : rv;
822      }
823
824      default:
825        warn("fcntl: unsupported command %d\n", cmd);
826        return 0;
827    }
828}
829
830SyscallReturn
831fcntl64Func(SyscallDesc *desc, int num, ThreadContext *tc)
832{
833    int index = 0;
834    auto p = tc->getProcessPtr();
835    int tgt_fd = p->getSyscallArg(tc, index);
836
837    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
838    if (!hbfdp)
839        return -EBADF;
840    int sim_fd = hbfdp->getSimFD();
841
842    int cmd = p->getSyscallArg(tc, index);
843    switch (cmd) {
844      case 33: //F_GETLK64
845        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
846        return -EMFILE;
847
848      case 34: // F_SETLK64
849      case 35: // F_SETLKW64
850        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
851             tgt_fd);
852        return -EMFILE;
853
854      default:
855        // not sure if this is totally valid, but we'll pass it through
856        // to the underlying OS
857        warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd);
858        return fcntl(sim_fd, cmd);
859    }
860}
861
862SyscallReturn
863pipeImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool pseudoPipe)
864{
865    int sim_fds[2], tgt_fds[2];
866    auto p = tc->getProcessPtr();
867
868    int pipe_retval = pipe(sim_fds);
869    if (pipe_retval == -1)
870        return -errno;
871
872    auto rend = PipeFDEntry::EndType::read;
873    auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
874    tgt_fds[0] = p->fds->allocFD(rpfd);
875
876    auto wend = PipeFDEntry::EndType::write;
877    auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
878    tgt_fds[1] = p->fds->allocFD(wpfd);
879
880    /**
881     * Now patch the read object to record the target file descriptor chosen
882     * as the write end of the pipe.
883     */
884    rpfd->setPipeReadSource(tgt_fds[1]);
885
886    /**
887     * Alpha Linux convention for pipe() is that fd[0] is returned as
888     * the return value of the function, and fd[1] is returned in r20.
889     */
890    if (pseudoPipe) {
891        tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
892        return tgt_fds[0];
893    }
894
895    int index = 0;
896    Addr tgt_addr = p->getSyscallArg(tc, index);
897
898    /**
899     * Copy the target file descriptors into buffer space and then copy
900     * the buffer space back into the target address space.
901     */
902    BufferArg tgt_handle(tgt_addr, sizeof(int[2]));
903    int *buf_ptr = (int*)tgt_handle.bufferPtr();
904    buf_ptr[0] = tgt_fds[0];
905    buf_ptr[1] = tgt_fds[1];
906    tgt_handle.copyOut(tc->getMemProxy());
907    return 0;
908}
909
910SyscallReturn
911pipePseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
912{
913    return pipeImpl(desc, callnum, tc, true);
914}
915
916SyscallReturn
917pipeFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
918{
919    return pipeImpl(desc, callnum, tc, false);
920}
921
922SyscallReturn
923setpgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
924{
925    int index = 0;
926    auto process = tc->getProcessPtr();
927    int pid = process->getSyscallArg(tc, index);
928    int pgid = process->getSyscallArg(tc, index);
929
930    if (pgid < 0)
931        return -EINVAL;
932
933    if (pid == 0) {
934        process->setpgid(process->pid());
935        return 0;
936    }
937
938    Process *matched_ph = nullptr;
939    System *sysh = tc->getSystemPtr();
940
941    // Retrieves process pointer from active/suspended thread contexts.
942    for (int i = 0; i < sysh->numContexts(); i++) {
943        if (sysh->threadContexts[i]->status() != ThreadContext::Halted) {
944            Process *temp_h = sysh->threadContexts[i]->getProcessPtr();
945            Process *walk_ph = (Process*)temp_h;
946
947            if (walk_ph && walk_ph->pid() == process->pid())
948                matched_ph = walk_ph;
949        }
950    }
951
952    assert(matched_ph);
953    matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid);
954
955    return 0;
956}
957
958SyscallReturn
959getpidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
960{
961    // Make up a PID.  There's no interprocess communication in
962    // fake_syscall mode, so there's no way for a process to know it's
963    // not getting a unique value.
964
965    auto process = tc->getProcessPtr();
966    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
967    return process->pid();
968}
969
970
971SyscallReturn
972getuidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
973{
974    // Make up a UID and EUID... it shouldn't matter, and we want the
975    // simulation to be deterministic.
976
977    // EUID goes in r20.
978    auto process = tc->getProcessPtr();
979    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID
980    return process->uid(); // UID
981}
982
983
984SyscallReturn
985getgidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
986{
987    // Get current group ID.  EGID goes in r20.
988    auto process = tc->getProcessPtr();
989    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID
990    return process->gid();
991}
992
993
994SyscallReturn
995setuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
996{
997    // can't fathom why a benchmark would call this.
998    int index = 0;
999    auto process = tc->getProcessPtr();
1000    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
1001    return 0;
1002}
1003
1004SyscallReturn
1005getpidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1006{
1007    auto process = tc->getProcessPtr();
1008    return process->tgid();
1009}
1010
1011SyscallReturn
1012gettidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1013{
1014    auto process = tc->getProcessPtr();
1015    return process->pid();
1016}
1017
1018SyscallReturn
1019getppidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1020{
1021    auto process = tc->getProcessPtr();
1022    return process->ppid();
1023}
1024
1025SyscallReturn
1026getuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1027{
1028    auto process = tc->getProcessPtr();
1029    return process->uid();              // UID
1030}
1031
1032SyscallReturn
1033geteuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1034{
1035    auto process = tc->getProcessPtr();
1036    return process->euid();             // UID
1037}
1038
1039SyscallReturn
1040getgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1041{
1042    auto process = tc->getProcessPtr();
1043    return process->gid();
1044}
1045
1046SyscallReturn
1047getegidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1048{
1049    auto process = tc->getProcessPtr();
1050    return process->egid();
1051}
1052
1053SyscallReturn
1054fallocateFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1055{
1056#if defined(__linux__)
1057    int index = 0;
1058    auto p = tc->getProcessPtr();
1059    int tgt_fd = p->getSyscallArg(tc, index);
1060    int mode = p->getSyscallArg(tc, index);
1061    off_t offset = p->getSyscallArg(tc, index);
1062    off_t len = p->getSyscallArg(tc, index);
1063
1064    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1065    if (!ffdp)
1066        return -EBADF;
1067    int sim_fd = ffdp->getSimFD();
1068
1069    int result = fallocate(sim_fd, mode, offset, len);
1070    if (result < 0)
1071        return -errno;
1072    return 0;
1073#else
1074    warnUnsupportedOS("fallocate");
1075    return -1;
1076#endif
1077}
1078
1079SyscallReturn
1080accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int index)
1081{
1082    string path;
1083    auto p = tc->getProcessPtr();
1084    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1085        return -EFAULT;
1086
1087    // Adjust path for cwd and redirection
1088    path = p->checkPathRedirect(path);
1089
1090    mode_t mode = p->getSyscallArg(tc, index);
1091
1092    int result = access(path.c_str(), mode);
1093    return (result == -1) ? -errno : result;
1094}
1095
1096SyscallReturn
1097accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1098{
1099    return accessFunc(desc, callnum, tc, 0);
1100}
1101
1102SyscallReturn
1103mknodFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1104{
1105    auto p = tc->getProcessPtr();
1106    int index = 0;
1107    std::string path;
1108    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1109        return -EFAULT;
1110
1111    path = p->checkPathRedirect(path);
1112    mode_t mode = p->getSyscallArg(tc, index);
1113    dev_t dev = p->getSyscallArg(tc, index);
1114
1115    auto result = mknod(path.c_str(), mode, dev);
1116    return (result == -1) ? -errno : result;
1117}
1118
1119SyscallReturn
1120chdirFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1121{
1122    auto p = tc->getProcessPtr();
1123    int index = 0;
1124    std::string path;
1125    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1126        return -EFAULT;
1127
1128    std::string tgt_cwd;
1129    if (startswith(path, "/")) {
1130        tgt_cwd = path;
1131    } else {
1132        char buf[PATH_MAX];
1133        tgt_cwd = realpath((p->tgtCwd + "/" + path).c_str(), buf);
1134    }
1135    std::string host_cwd = p->checkPathRedirect(tgt_cwd);
1136
1137    int result = chdir(host_cwd.c_str());
1138
1139    if (result == -1)
1140        return -errno;
1141
1142    p->hostCwd = host_cwd;
1143    p->tgtCwd = tgt_cwd;
1144    return result;
1145}
1146
1147SyscallReturn
1148rmdirFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1149{
1150    auto p = tc->getProcessPtr();
1151    int index = 0;
1152    std::string path;
1153    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1154        return -EFAULT;
1155
1156    path = p->checkPathRedirect(path);
1157
1158    auto result = rmdir(path.c_str());
1159    return (result == -1) ? -errno : result;
1160}
1161
1162#if defined(SYS_getdents) || defined(SYS_getdents64)
1163template<typename DE, int SYS_NUM>
1164static SyscallReturn
1165getdentsImpl(SyscallDesc *desc, int callnum, ThreadContext *tc)
1166{
1167    int index = 0;
1168    auto p = tc->getProcessPtr();
1169    int tgt_fd = p->getSyscallArg(tc, index);
1170    Addr buf_ptr = p->getSyscallArg(tc, index);
1171    unsigned count = p->getSyscallArg(tc, index);
1172
1173    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1174    if (!hbfdp)
1175        return -EBADF;
1176    int sim_fd = hbfdp->getSimFD();
1177
1178    BufferArg buf_arg(buf_ptr, count);
1179    auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count);
1180
1181    if (status == -1)
1182        return -errno;
1183
1184    unsigned traversed = 0;
1185    while (traversed < status) {
1186        DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed);
1187
1188        auto host_reclen = buffer->d_reclen;
1189
1190        /**
1191         * Convert the byte ordering from the host to the target before
1192         * passing the data back into the target's address space to preserve
1193         * endianness.
1194         */
1195        buffer->d_ino = htog(buffer->d_ino);
1196        buffer->d_off = htog(buffer->d_off);
1197        buffer->d_reclen = htog(buffer->d_reclen);
1198
1199        traversed += host_reclen;
1200    }
1201
1202    buf_arg.copyOut(tc->getMemProxy());
1203    return status;
1204}
1205#endif
1206
1207#if defined(SYS_getdents)
1208SyscallReturn
1209getdentsFunc(SyscallDesc *desc, int callnum, ThreadContext *tc)
1210{
1211    typedef struct linux_dirent {
1212        unsigned long d_ino;
1213        unsigned long d_off;
1214        unsigned short d_reclen;
1215        char dname[];
1216    } LinDent;
1217
1218    return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, tc);
1219}
1220#endif
1221
1222#if defined(SYS_getdents64)
1223SyscallReturn
1224getdents64Func(SyscallDesc *desc, int callnum, ThreadContext *tc)
1225{
1226    typedef struct linux_dirent64 {
1227        ino64_t d_ino;
1228        off64_t d_off;
1229        unsigned short d_reclen;
1230        char dname[];
1231    } LinDent64;
1232
1233    return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, tc);
1234}
1235#endif
1236
1237SyscallReturn
1238shutdownFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1239{
1240    int index = 0;
1241    auto p = tc->getProcessPtr();
1242    int tgt_fd = p->getSyscallArg(tc, index);
1243    int how = p->getSyscallArg(tc, index);
1244
1245    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1246    if (!sfdp)
1247        return -EBADF;
1248    int sim_fd = sfdp->getSimFD();
1249
1250    int retval = shutdown(sim_fd, how);
1251
1252    return (retval == -1) ? -errno : retval;
1253}
1254
1255SyscallReturn
1256bindFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1257{
1258    int index = 0;
1259    auto p = tc->getProcessPtr();
1260    int tgt_fd = p->getSyscallArg(tc, index);
1261    Addr buf_ptr = p->getSyscallArg(tc, index);
1262    int addrlen = p->getSyscallArg(tc, index);
1263
1264    BufferArg bufSock(buf_ptr, addrlen);
1265    bufSock.copyIn(tc->getMemProxy());
1266
1267    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1268    if (!sfdp)
1269        return -EBADF;
1270    int sim_fd = sfdp->getSimFD();
1271
1272    int status = ::bind(sim_fd,
1273                        (struct sockaddr *)bufSock.bufferPtr(),
1274                        addrlen);
1275
1276    return (status == -1) ? -errno : status;
1277}
1278
1279SyscallReturn
1280listenFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1281{
1282    int index = 0;
1283    auto p = tc->getProcessPtr();
1284    int tgt_fd = p->getSyscallArg(tc, index);
1285    int backlog = p->getSyscallArg(tc, index);
1286
1287    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1288    if (!sfdp)
1289        return -EBADF;
1290    int sim_fd = sfdp->getSimFD();
1291
1292    int status = listen(sim_fd, backlog);
1293
1294    return (status == -1) ? -errno : status;
1295}
1296
1297SyscallReturn
1298connectFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1299{
1300    int index = 0;
1301    auto p = tc->getProcessPtr();
1302    int tgt_fd = p->getSyscallArg(tc, index);
1303    Addr buf_ptr = p->getSyscallArg(tc, index);
1304    int addrlen = p->getSyscallArg(tc, index);
1305
1306    BufferArg addr(buf_ptr, addrlen);
1307    addr.copyIn(tc->getMemProxy());
1308
1309    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1310    if (!sfdp)
1311        return -EBADF;
1312    int sim_fd = sfdp->getSimFD();
1313
1314    int status = connect(sim_fd,
1315                         (struct sockaddr *)addr.bufferPtr(),
1316                         (socklen_t)addrlen);
1317
1318    return (status == -1) ? -errno : status;
1319}
1320
1321SyscallReturn
1322recvfromFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1323{
1324    int index = 0;
1325    auto p = tc->getProcessPtr();
1326    int tgt_fd = p->getSyscallArg(tc, index);
1327    Addr bufrPtr = p->getSyscallArg(tc, index);
1328    size_t bufrLen = p->getSyscallArg(tc, index);
1329    int flags = p->getSyscallArg(tc, index);
1330    Addr addrPtr = p->getSyscallArg(tc, index);
1331    Addr addrlenPtr = p->getSyscallArg(tc, index);
1332
1333    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1334    if (!sfdp)
1335        return -EBADF;
1336    int sim_fd = sfdp->getSimFD();
1337
1338    // Reserve buffer space.
1339    BufferArg bufrBuf(bufrPtr, bufrLen);
1340
1341    // Get address length.
1342    socklen_t addrLen = 0;
1343    if (addrlenPtr != 0) {
1344        // Read address length parameter.
1345        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1346        addrlenBuf.copyIn(tc->getMemProxy());
1347        addrLen = *((socklen_t *)addrlenBuf.bufferPtr());
1348    }
1349
1350    struct sockaddr sa, *sap = NULL;
1351    if (addrLen != 0) {
1352        BufferArg addrBuf(addrPtr, addrLen);
1353        addrBuf.copyIn(tc->getMemProxy());
1354        memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(),
1355               sizeof(struct sockaddr));
1356        sap = &sa;
1357    }
1358
1359    ssize_t recvd_size = recvfrom(sim_fd,
1360                                  (void *)bufrBuf.bufferPtr(),
1361                                  bufrLen, flags, sap, (socklen_t *)&addrLen);
1362
1363    if (recvd_size == -1)
1364        return -errno;
1365
1366    // Pass the received data out.
1367    bufrBuf.copyOut(tc->getMemProxy());
1368
1369    // Copy address to addrPtr and pass it on.
1370    if (sap != NULL) {
1371        BufferArg addrBuf(addrPtr, addrLen);
1372        memcpy(addrBuf.bufferPtr(), sap, sizeof(sa));
1373        addrBuf.copyOut(tc->getMemProxy());
1374    }
1375
1376    // Copy len to addrlenPtr and pass it on.
1377    if (addrLen != 0) {
1378        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1379        *(socklen_t *)addrlenBuf.bufferPtr() = addrLen;
1380        addrlenBuf.copyOut(tc->getMemProxy());
1381    }
1382
1383    return recvd_size;
1384}
1385
1386SyscallReturn
1387sendtoFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1388{
1389    int index = 0;
1390    auto p = tc->getProcessPtr();
1391    int tgt_fd = p->getSyscallArg(tc, index);
1392    Addr bufrPtr = p->getSyscallArg(tc, index);
1393    size_t bufrLen = p->getSyscallArg(tc, index);
1394    int flags = p->getSyscallArg(tc, index);
1395    Addr addrPtr = p->getSyscallArg(tc, index);
1396    socklen_t addrLen = p->getSyscallArg(tc, index);
1397
1398    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1399    if (!sfdp)
1400        return -EBADF;
1401    int sim_fd = sfdp->getSimFD();
1402
1403    // Reserve buffer space.
1404    BufferArg bufrBuf(bufrPtr, bufrLen);
1405    bufrBuf.copyIn(tc->getMemProxy());
1406
1407    struct sockaddr sa, *sap = nullptr;
1408    memset(&sa, 0, sizeof(sockaddr));
1409    if (addrLen != 0) {
1410        BufferArg addrBuf(addrPtr, addrLen);
1411        addrBuf.copyIn(tc->getMemProxy());
1412        memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen);
1413        sap = &sa;
1414    }
1415
1416    ssize_t sent_size = sendto(sim_fd,
1417                               (void *)bufrBuf.bufferPtr(),
1418                               bufrLen, flags, sap, (socklen_t)addrLen);
1419
1420    return (sent_size == -1) ? -errno : sent_size;
1421}
1422
1423SyscallReturn
1424recvmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1425{
1426    int index = 0;
1427    auto p = tc->getProcessPtr();
1428    int tgt_fd = p->getSyscallArg(tc, index);
1429    Addr msgPtr = p->getSyscallArg(tc, index);
1430    int flags = p->getSyscallArg(tc, index);
1431
1432    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1433    if (!sfdp)
1434        return -EBADF;
1435    int sim_fd = sfdp->getSimFD();
1436
1437     /**
1438      *  struct msghdr {
1439      *     void         *msg_name;       // optional address
1440      *    socklen_t     msg_namelen;    // size of address
1441      *    struct iovec *msg_iov;        // iovec array
1442      *    size_t        msg_iovlen;     // number entries in msg_iov
1443      *    i                             // entries correspond to buffer
1444      *    void         *msg_control;    // ancillary data
1445      *    size_t        msg_controllen; // ancillary data buffer len
1446      *    int           msg_flags;      // flags on received message
1447      *  };
1448      *
1449      *  struct iovec {
1450      *    void  *iov_base;              // starting address
1451      *    size_t iov_len;               // number of bytes to transfer
1452      *  };
1453      */
1454
1455    /**
1456     * The plan with this system call is to replace all of the pointers in the
1457     * structure and the substructure with BufferArg class pointers. We will
1458     * copy every field from the structures into our BufferArg classes.
1459     */
1460    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1461    msgBuf.copyIn(tc->getMemProxy());
1462    struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr();
1463
1464    /**
1465     * We will use these address place holders to retain the pointers which
1466     * we are going to replace with our own buffers in our simulator address
1467     * space.
1468     */
1469    Addr msg_name_phold = 0;
1470    Addr msg_iov_phold = 0;
1471    Addr iovec_base_phold[msgHdr->msg_iovlen];
1472    Addr msg_control_phold = 0;
1473
1474    /**
1475     * Record msg_name pointer then replace with buffer pointer.
1476     */
1477    BufferArg *nameBuf = NULL;
1478    if (msgHdr->msg_name) {
1479        /*1*/msg_name_phold = (Addr)msgHdr->msg_name;
1480        /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen);
1481        /*3*/nameBuf->copyIn(tc->getMemProxy());
1482        /*4*/msgHdr->msg_name = nameBuf->bufferPtr();
1483    }
1484
1485    /**
1486     * Record msg_iov pointer then replace with buffer pointer. Also, setup
1487     * an array of buffer pointers for the iovec structs record and replace
1488     * their pointers with buffer pointers.
1489     */
1490    BufferArg *iovBuf = NULL;
1491    BufferArg *iovecBuf[msgHdr->msg_iovlen];
1492    for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1493        iovec_base_phold[i] = 0;
1494        iovecBuf[i] = NULL;
1495    }
1496
1497    if (msgHdr->msg_iov) {
1498        /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov;
1499        /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen *
1500                                    sizeof(struct iovec));
1501        /*3*/iovBuf->copyIn(tc->getMemProxy());
1502        for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1503            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1504                /*1*/iovec_base_phold[i] =
1505                     (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base;
1506                /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i],
1507                     ((struct iovec *)iovBuf->bufferPtr())[i].iov_len);
1508                /*3*/iovecBuf[i]->copyIn(tc->getMemProxy());
1509                /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1510                     iovecBuf[i]->bufferPtr();
1511            }
1512        }
1513        /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr();
1514    }
1515
1516    /**
1517     * Record msg_control pointer then replace with buffer pointer.
1518     */
1519    BufferArg *controlBuf = NULL;
1520    if (msgHdr->msg_control) {
1521        /*1*/msg_control_phold = (Addr)msgHdr->msg_control;
1522        /*2*/controlBuf = new BufferArg(msg_control_phold,
1523                                        CMSG_ALIGN(msgHdr->msg_controllen));
1524        /*3*/controlBuf->copyIn(tc->getMemProxy());
1525        /*4*/msgHdr->msg_control = controlBuf->bufferPtr();
1526    }
1527
1528    ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags);
1529
1530    if (recvd_size < 0)
1531        return -errno;
1532
1533    if (msgHdr->msg_name) {
1534        nameBuf->copyOut(tc->getMemProxy());
1535        delete(nameBuf);
1536        msgHdr->msg_name = (void *)msg_name_phold;
1537    }
1538
1539    if (msgHdr->msg_iov) {
1540        for (int i = 0; i< msgHdr->msg_iovlen; i++) {
1541            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1542                iovecBuf[i]->copyOut(tc->getMemProxy());
1543                delete iovecBuf[i];
1544                ((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1545                (void *)iovec_base_phold[i];
1546            }
1547        }
1548        iovBuf->copyOut(tc->getMemProxy());
1549        delete iovBuf;
1550        msgHdr->msg_iov = (struct iovec *)msg_iov_phold;
1551    }
1552
1553    if (msgHdr->msg_control) {
1554        controlBuf->copyOut(tc->getMemProxy());
1555        delete(controlBuf);
1556        msgHdr->msg_control = (void *)msg_control_phold;
1557    }
1558
1559    msgBuf.copyOut(tc->getMemProxy());
1560
1561    return recvd_size;
1562}
1563
1564SyscallReturn
1565sendmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1566{
1567    int index = 0;
1568    auto p = tc->getProcessPtr();
1569    int tgt_fd = p->getSyscallArg(tc, index);
1570    Addr msgPtr = p->getSyscallArg(tc, index);
1571    int flags = p->getSyscallArg(tc, index);
1572
1573    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1574    if (!sfdp)
1575        return -EBADF;
1576    int sim_fd = sfdp->getSimFD();
1577
1578    /**
1579     * Reserve buffer space.
1580     */
1581    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1582    msgBuf.copyIn(tc->getMemProxy());
1583    struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr());
1584
1585    /**
1586     * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
1587     * recvmsg without a buffer.
1588     */
1589    struct iovec *iovPtr = msgHdr.msg_iov;
1590    BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen);
1591    iovBuf.copyIn(tc->getMemProxy());
1592    struct iovec *iov = (struct iovec *)iovBuf.bufferPtr();
1593    msgHdr.msg_iov = iov;
1594
1595    /**
1596     * Cannot instantiate buffers till inside the loop.
1597     * Create array to hold buffer addresses, to be used during copyIn of
1598     * send data.
1599     */
1600    BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen
1601                                                   * sizeof(BufferArg *));
1602
1603    /**
1604     * Iterate through the iovec structures:
1605     * Get the base buffer addreses, reserve iov_len amount of space for each.
1606     * Put the buf address into the bufferArray for later retrieval.
1607     */
1608    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1609        Addr basePtr = (Addr) iov[iovIndex].iov_base;
1610        bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len);
1611        bufferArray[iovIndex]->copyIn(tc->getMemProxy());
1612        iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr();
1613    }
1614
1615    ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags);
1616    int local_errno = errno;
1617
1618    /**
1619     * Free dynamically allocated memory.
1620     */
1621    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1622        BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex];
1623        delete(baseBuf);
1624    }
1625
1626    /**
1627     * Malloced above.
1628     */
1629    free(bufferArray);
1630
1631    return (sent_size < 0) ? -local_errno : sent_size;
1632}
1633
1634SyscallReturn
1635getsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1636{
1637    // union of all possible return value types from getsockopt
1638    union val {
1639        int i_val;
1640        long l_val;
1641        struct linger linger_val;
1642        struct timeval timeval_val;
1643    } val;
1644
1645    int index = 0;
1646    auto p = tc->getProcessPtr();
1647    int tgt_fd = p->getSyscallArg(tc, index);
1648    int level = p->getSyscallArg(tc, index);
1649    int optname = p->getSyscallArg(tc, index);
1650    Addr valPtr = p->getSyscallArg(tc, index);
1651    Addr lenPtr = p->getSyscallArg(tc, index);
1652
1653    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1654    if (!sfdp)
1655        return -EBADF;
1656    int sim_fd = sfdp->getSimFD();
1657
1658    socklen_t len = sizeof(val);
1659    int status = getsockopt(sim_fd, level, optname, &val, &len);
1660
1661    if (status == -1)
1662        return -errno;
1663
1664    // copy val to valPtr and pass it on
1665    BufferArg valBuf(valPtr, sizeof(val));
1666    memcpy(valBuf.bufferPtr(), &val, sizeof(val));
1667    valBuf.copyOut(tc->getMemProxy());
1668
1669    // copy len to lenPtr and pass  it on
1670    BufferArg lenBuf(lenPtr, sizeof(len));
1671    memcpy(lenBuf.bufferPtr(), &len, sizeof(len));
1672    lenBuf.copyOut(tc->getMemProxy());
1673
1674    return status;
1675}
1676
1677SyscallReturn
1678getsocknameFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1679{
1680    int index = 0;
1681    auto p = tc->getProcessPtr();
1682    int tgt_fd = p->getSyscallArg(tc, index);
1683    Addr addrPtr = p->getSyscallArg(tc, index);
1684    Addr lenPtr = p->getSyscallArg(tc, index);
1685
1686    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1687    if (!sfdp)
1688        return -EBADF;
1689    int sim_fd = sfdp->getSimFD();
1690
1691    // lenPtr is an in-out paramenter:
1692    // sending the address length in, conveying the final length out
1693
1694    // Read in the value of len from the passed pointer.
1695    BufferArg lenBuf(lenPtr, sizeof(socklen_t));
1696    lenBuf.copyIn(tc->getMemProxy());
1697    socklen_t len = *(socklen_t *)lenBuf.bufferPtr();
1698
1699    struct sockaddr sa;
1700    int status = getsockname(sim_fd, &sa, &len);
1701
1702    if (status == -1)
1703        return -errno;
1704
1705    // Copy address to addrPtr and pass it on.
1706    BufferArg addrBuf(addrPtr, sizeof(sa));
1707    memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa));
1708    addrBuf.copyOut(tc->getMemProxy());
1709
1710    // Copy len to lenPtr and pass  it on.
1711    *(socklen_t *)lenBuf.bufferPtr() = len;
1712    lenBuf.copyOut(tc->getMemProxy());
1713
1714    return status;
1715}
1716
1717SyscallReturn
1718getpeernameFunc(SyscallDesc *desc, int num, ThreadContext *tc)
1719{
1720    int index = 0;
1721    auto p = tc->getProcessPtr();
1722    int tgt_fd = p->getSyscallArg(tc, index);
1723    Addr sockAddrPtr = p->getSyscallArg(tc, index);
1724    Addr addrlenPtr = p->getSyscallArg(tc, index);
1725
1726    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1727    if (!sfdp)
1728        return -EBADF;
1729    int sim_fd = sfdp->getSimFD();
1730
1731    BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned));
1732    bufAddrlen.copyIn(tc->getMemProxy());
1733    BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr());
1734
1735    int retval = getpeername(sim_fd,
1736                             (struct sockaddr *)bufSock.bufferPtr(),
1737                             (unsigned *)bufAddrlen.bufferPtr());
1738
1739    if (retval != -1) {
1740        bufSock.copyOut(tc->getMemProxy());
1741        bufAddrlen.copyOut(tc->getMemProxy());
1742    }
1743
1744    return (retval == -1) ? -errno : retval;
1745}
1746
1747SyscallReturn
1748setsockoptFunc(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    int level = p->getSyscallArg(tc, index);
1754    int optname = p->getSyscallArg(tc, index);
1755    Addr valPtr = p->getSyscallArg(tc, index);
1756    socklen_t len = p->getSyscallArg(tc, index);
1757
1758    BufferArg valBuf(valPtr, len);
1759    valBuf.copyIn(tc->getMemProxy());
1760
1761    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1762    if (!sfdp)
1763        return -EBADF;
1764    int sim_fd = sfdp->getSimFD();
1765
1766    int status = setsockopt(sim_fd, level, optname,
1767                            (struct sockaddr *)valBuf.bufferPtr(), len);
1768
1769    return (status == -1) ? -errno : status;
1770}
1771
1772