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