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