syscall_emul.cc revision 13571
11689SN/A/*
29437SAndreas.Sandberg@ARM.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
37855SAli.Saidi@ARM.com * All rights reserved.
47855SAli.Saidi@ARM.com *
57855SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
67855SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
77855SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright
87855SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer;
97855SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
107855SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
117855SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
127855SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
137855SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
142316SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271689SN/A *
281689SN/A * Authors: Steve Reinhardt
291689SN/A *          Ali Saidi
301689SN/A */
311689SN/A
321689SN/A#include "sim/syscall_emul.hh"
331689SN/A
341689SN/A#include <fcntl.h>
351689SN/A#include <sys/syscall.h>
361689SN/A#include <unistd.h>
371689SN/A
381689SN/A#include <csignal>
392665Ssaidi@eecs.umich.edu#include <iostream>
402665Ssaidi@eecs.umich.edu#include <mutex>
412756Sksewell@umich.edu#include <string>
421689SN/A
431689SN/A#include "arch/utility.hh"
442292SN/A#include "base/chunk_generator.hh"
452292SN/A#include "base/trace.hh"
461060SN/A#include "config/the_isa.hh"
478230Snate@binkert.org#include "cpu/thread_context.hh"
488230Snate@binkert.org#include "dev/net/dist_iface.hh"
491461SN/A#include "mem/page_table.hh"
502292SN/A#include "sim/byteswap.hh"
512329SN/A#include "sim/process.hh"
528229Snate@binkert.org#include "sim/sim_exit.hh"
531060SN/A#include "sim/syscall_debug_macros.hh"
548737Skoansin.tan@gmail.com#include "sim/syscall_desc.hh"
555529Snate@binkert.org#include "sim/system.hh"
562292SN/A
578737Skoansin.tan@gmail.comusing namespace std;
582292SN/Ausing namespace TheISA;
592292SN/A
602316SN/ASyscallReturn
612316SN/AunimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
622316SN/A                  ThreadContext *tc)
632316SN/A{
642316SN/A    fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum);
652316SN/A
662316SN/A    return 1;
672316SN/A}
682316SN/A
692316SN/A
702316SN/ASyscallReturn
712316SN/AignoreFunc(SyscallDesc *desc, int callnum, Process *process,
722316SN/A           ThreadContext *tc)
732316SN/A{
742316SN/A    if (desc->needWarning()) {
752316SN/A        warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ?
762316SN/A             "\n      (further warnings will be suppressed)" : "");
772316SN/A    }
782316SN/A
792329SN/A    return 0;
802292SN/A}
811060SN/A
822292SN/Astatic void
831060SN/AexitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid)
841060SN/A{
851060SN/A    // Clear value at address pointed to by thread's childClearTID field.
862733Sktlim@umich.edu    BufferArg ctidBuf(addr, sizeof(long));
871061SN/A    long *ctid = (long *)ctidBuf.bufferPtr();
881061SN/A    *ctid = 0;
891060SN/A    ctidBuf.copyOut(tc->getMemProxy());
902292SN/A
911061SN/A    FutexMap &futex_map = tc->getSystemPtr()->futexMap;
921060SN/A    // Wake one of the waiting threads.
931061SN/A    futex_map.wakeup(addr, tgid, 1);
942292SN/A}
951061SN/A
961061SN/Astatic SyscallReturn
971060SN/AexitImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
982316SN/A         bool group)
992292SN/A{
1002292SN/A    int index = 0;
1012292SN/A    int status = p->getSyscallArg(tc, index);
1022292SN/A
1032348SN/A    System *sys = tc->getSystemPtr();
1042348SN/A
1052348SN/A    int activeContexts = 0;
1062292SN/A    for (auto &system: sys->systemList)
1072292SN/A        activeContexts += system->numRunningContexts();
1082292SN/A    if (activeContexts == 1) {
1096221Snate@binkert.org        /**
1102292SN/A         * Even though we are terminating the final thread context, dist-gem5
1112292SN/A         * requires the simulation to remain active and provide
1126221Snate@binkert.org         * synchronization messages to the switch process. So we just halt
1132292SN/A         * the last thread context and return. The simulation will be
1142292SN/A         * terminated by dist-gem5 in a coordinated manner once all nodes
1155336Shines@cs.fsu.edu         * have signaled their readiness to exit. For non dist-gem5
1162292SN/A         * simulations, readyToExit() always returns true.
1172292SN/A         */
1182292SN/A        if (!DistIface::readyToExit(0)) {
1192292SN/A            tc->halt();
1202292SN/A            return status;
1212292SN/A        }
1222292SN/A
1232292SN/A        exitSimLoop("exiting with last active thread context", status & 0xff);
1242292SN/A        return status;
1252292SN/A    }
1262292SN/A
1272292SN/A    if (group)
1281060SN/A        *p->exitGroup = true;
1291060SN/A
1301060SN/A    if (p->childClearTID)
1312292SN/A        exitFutexWake(tc, p->childClearTID, p->tgid());
1329437SAndreas.Sandberg@ARM.com
1339437SAndreas.Sandberg@ARM.com    bool last_thread = true;
1342292SN/A    Process *parent = nullptr, *tg_lead = nullptr;
1352292SN/A    for (int i = 0; last_thread && i < sys->numContexts(); i++) {
1362292SN/A        Process *walk;
1372292SN/A        if (!(walk = sys->threadContexts[i]->getProcessPtr()))
1382292SN/A            continue;
1392292SN/A
1402292SN/A        /**
1411060SN/A         * Threads in a thread group require special handing. For instance,
1421060SN/A         * we send the SIGCHLD signal so that it appears that it came from
1431060SN/A         * the head of the group. We also only delete file descriptors if
1442292SN/A         * we are the last thread in the thread group.
1452292SN/A         */
1462292SN/A        if (walk->pid() == p->tgid())
1472292SN/A            tg_lead = walk;
1482292SN/A
1492292SN/A        if ((sys->threadContexts[i]->status() != ThreadContext::Halted)
1502292SN/A            && (walk != p)) {
1512292SN/A            /**
1521060SN/A             * Check if we share thread group with the pointer; this denotes
1531060SN/A             * that we are not the last thread active in the thread group.
1542292SN/A             * Note that setting this to false also prevents further
1555529Snate@binkert.org             * iterations of the loop.
1561060SN/A             */
1572292SN/A            if (walk->tgid() == p->tgid())
1582292SN/A                last_thread = false;
1592292SN/A
1602292SN/A            /**
1611062SN/A             * A corner case exists which involves execve(). After execve(),
1621062SN/A             * the execve will enable SIGCHLD in the process. The problem
1632292SN/A             * occurs when the exiting process is the root process in the
1642292SN/A             * system; there is no parent to receive the signal. We obviate
1652292SN/A             * this problem by setting the root process' ppid to zero in the
1662292SN/A             * Python configuration files. We really should handle the
1671060SN/A             * root/execve specific case more gracefully.
1681060SN/A             */
1692292SN/A            if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid()))
1702292SN/A                parent = walk;
1712292SN/A        }
1721060SN/A    }
1731060SN/A
1742292SN/A    if (last_thread) {
1751060SN/A        if (parent) {
1761060SN/A            assert(tg_lead);
1772348SN/A            sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD));
1782292SN/A        }
1792292SN/A
1802965Sksewell@umich.edu        /**
1812965Sksewell@umich.edu         * Run though FD array of the exiting process and close all file
1822965Sksewell@umich.edu         * descriptors except for the standard file descriptors.
1832316SN/A         * (The standard file descriptors are shared with gem5.)
1842316SN/A         */
1852316SN/A        for (int i = 0; i < p->fds->getSize(); i++) {
1862292SN/A            if ((*p->fds)[i])
1872292SN/A                p->fds->closeFDEntry(i);
1882292SN/A        }
1892292SN/A    }
1906221Snate@binkert.org
1912292SN/A    tc->halt();
1922292SN/A    return status;
1932292SN/A}
1942292SN/A
1952292SN/ASyscallReturn
1961060SN/AexitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1971060SN/A{
1982292SN/A    return exitImpl(desc, callnum, p, tc, false);
1999427SAndreas.Sandberg@ARM.com}
2002292SN/A
2012843Sktlim@umich.eduSyscallReturn
2022863Sktlim@umich.eduexitGroupFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
2032843Sktlim@umich.edu{
2042843Sktlim@umich.edu    return exitImpl(desc, callnum, p, tc, true);
2052843Sktlim@umich.edu}
2062307SN/A
2072348SN/ASyscallReturn
2082843Sktlim@umich.edugetpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2092316SN/A{
2102348SN/A    return (int)PageBytes;
2112307SN/A}
2122307SN/A
2132292SN/A
2141060SN/ASyscallReturn
2151060SN/AbrkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2162292SN/A{
2172292SN/A    // change brk addr to first arg
2182292SN/A    int index = 0;
2191060SN/A    Addr new_brk = p->getSyscallArg(tc, index);
2201060SN/A
2212292SN/A    std::shared_ptr<MemState> mem_state = p->memState;
2226221Snate@binkert.org    Addr brk_point = mem_state->getBrkPoint();
2232292SN/A
2242348SN/A    // in Linux at least, brk(0) returns the current break value
2256221Snate@binkert.org    // (note that the syscall and the glibc function have different behavior)
2262348SN/A    if (new_brk == 0)
2272348SN/A        return brk_point;
2282680Sktlim@umich.edu
2292348SN/A    if (new_brk > brk_point) {
2306221Snate@binkert.org        // might need to allocate some new pages
2312292SN/A        for (ChunkGenerator gen(brk_point,
2321060SN/A                                new_brk - brk_point,
2332292SN/A                                PageBytes); !gen.done(); gen.next()) {
2342348SN/A            if (!p->pTable->translate(gen.addr()))
2352348SN/A                p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
2362292SN/A
2371060SN/A            // if the address is already there, zero it out
2382292SN/A            else {
2392292SN/A                uint8_t zero = 0;
2402292SN/A                SETranslatingPortProxy &tp = tc->getMemProxy();
2412292SN/A
2422292SN/A                // split non-page aligned accesses
2432292SN/A                Addr next_page = roundUp(gen.addr(), PageBytes);
2442292SN/A                uint32_t size_needed = next_page - gen.addr();
2452292SN/A                tp.memsetBlob(gen.addr(), zero, size_needed);
2462292SN/A                if (gen.addr() + PageBytes > next_page &&
2472292SN/A                    next_page < new_brk &&
2482292SN/A                    p->pTable->translate(next_page)) {
2492292SN/A                    size_needed = PageBytes - size_needed;
2502292SN/A                    tp.memsetBlob(next_page, zero, size_needed);
2512292SN/A                }
2522292SN/A            }
2532292SN/A        }
2542348SN/A    }
2556221Snate@binkert.org
2562316SN/A    mem_state->setBrkPoint(new_brk);
2572348SN/A    DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
2586221Snate@binkert.org                    mem_state->getBrkPoint());
2592292SN/A    return mem_state->getBrkPoint();
2602680Sktlim@umich.edu}
2616221Snate@binkert.org
2622292SN/ASyscallReturn
2639437SAndreas.Sandberg@ARM.comsetTidAddressFunc(SyscallDesc *desc, int callnum, Process *process,
2649437SAndreas.Sandberg@ARM.com                  ThreadContext *tc)
2659437SAndreas.Sandberg@ARM.com{
2669437SAndreas.Sandberg@ARM.com    int index = 0;
2679437SAndreas.Sandberg@ARM.com    uint64_t tidPtr = process->getSyscallArg(tc, index);
2689437SAndreas.Sandberg@ARM.com
2697784SAli.Saidi@ARM.com    process->childClearTID = tidPtr;
2707784SAli.Saidi@ARM.com    return process->pid();
2719437SAndreas.Sandberg@ARM.com}
2729437SAndreas.Sandberg@ARM.com
2739437SAndreas.Sandberg@ARM.comSyscallReturn
2749437SAndreas.Sandberg@ARM.comcloseFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2759437SAndreas.Sandberg@ARM.com{
2769437SAndreas.Sandberg@ARM.com    int index = 0;
2779437SAndreas.Sandberg@ARM.com    int tgt_fd = p->getSyscallArg(tc, index);
2789437SAndreas.Sandberg@ARM.com
2799437SAndreas.Sandberg@ARM.com    return p->fds->closeFDEntry(tgt_fd);
2809437SAndreas.Sandberg@ARM.com}
2819437SAndreas.Sandberg@ARM.com
2829437SAndreas.Sandberg@ARM.comSyscallReturn
2839437SAndreas.Sandberg@ARM.comlseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2849437SAndreas.Sandberg@ARM.com{
2859437SAndreas.Sandberg@ARM.com    int index = 0;
2869437SAndreas.Sandberg@ARM.com    int tgt_fd = p->getSyscallArg(tc, index);
2879437SAndreas.Sandberg@ARM.com    uint64_t offs = p->getSyscallArg(tc, index);
2889437SAndreas.Sandberg@ARM.com    int whence = p->getSyscallArg(tc, index);
2899437SAndreas.Sandberg@ARM.com
2909437SAndreas.Sandberg@ARM.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
2919437SAndreas.Sandberg@ARM.com    if (!ffdp)
2929437SAndreas.Sandberg@ARM.com        return -EBADF;
2937784SAli.Saidi@ARM.com    int sim_fd = ffdp->getSimFD();
2949437SAndreas.Sandberg@ARM.com
2957784SAli.Saidi@ARM.com    off_t result = lseek(sim_fd, offs, whence);
2964035Sktlim@umich.edu
2974035Sktlim@umich.edu    return (result == (off_t)-1) ? -errno : result;
2987847Sminkyu.jeong@arm.com}
2997847Sminkyu.jeong@arm.com
3007847Sminkyu.jeong@arm.com
3014035Sktlim@umich.eduSyscallReturn
3022292SN/A_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
3031060SN/A{
3041060SN/A    int index = 0;
3052292SN/A    int tgt_fd = p->getSyscallArg(tc, index);
3062292SN/A    uint64_t offset_high = p->getSyscallArg(tc, index);
3072292SN/A    uint32_t offset_low = p->getSyscallArg(tc, index);
3081061SN/A    Addr result_ptr = p->getSyscallArg(tc, index);
3091060SN/A    int whence = p->getSyscallArg(tc, index);
3102292SN/A
3111060SN/A    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
3121060SN/A    if (!ffdp)
3132965Sksewell@umich.edu        return -EBADF;
3142965Sksewell@umich.edu    int sim_fd = ffdp->getSimFD();
3152965Sksewell@umich.edu
3162292SN/A    uint64_t offset = (offset_high << 32) | offset_low;
3171060SN/A
3181060SN/A    uint64_t result = lseek(sim_fd, offset, whence);
3192292SN/A    result = TheISA::htog(result);
3206221Snate@binkert.org
3212292SN/A    if (result == (off_t)-1)
3222292SN/A        return -errno;
3236221Snate@binkert.org    // Assuming that the size of loff_t is 64 bits on the target platform
3242292SN/A    BufferArg result_buf(result_ptr, sizeof(result));
3252292SN/A    memcpy(result_buf.bufferPtr(), &result, sizeof(result));
3266221Snate@binkert.org    result_buf.copyOut(tc->getMemProxy());
3272292SN/A    return 0;
3281684SN/A}
3297720Sgblack@eecs.umich.edu
3307720Sgblack@eecs.umich.edu
3317720Sgblack@eecs.umich.eduSyscallReturn
3327720Sgblack@eecs.umich.edumunmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
3337720Sgblack@eecs.umich.edu{
3347720Sgblack@eecs.umich.edu    // With mmap more fully implemented, it might be worthwhile to bite
3351684SN/A    // the bullet and implement munmap. Should allow us to reuse simulated
3362348SN/A    // memory.
3377720Sgblack@eecs.umich.edu    return 0;
3382292SN/A}
3397720Sgblack@eecs.umich.edu
3407720Sgblack@eecs.umich.edu
3414636Sgblack@eecs.umich.educonst char *hostname = "m5.eecs.umich.edu";
3424636Sgblack@eecs.umich.edu
3437720Sgblack@eecs.umich.eduSyscallReturn
3442756Sksewell@umich.edugethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
3451684SN/A{
3461060SN/A    int index = 0;
3471060SN/A    Addr buf_ptr = p->getSyscallArg(tc, index);
3481060SN/A    int name_len = p->getSyscallArg(tc, index);
3491060SN/A    BufferArg name(buf_ptr, name_len);
3501060SN/A
3511060SN/A    strncpy((char *)name.bufferPtr(), hostname, name_len);
3521060SN/A
3531060SN/A    name.copyOut(tc->getMemProxy());
3541060SN/A
3552292SN/A    return 0;
3562292SN/A}
3572292SN/A
3582292SN/ASyscallReturn
3591060SN/AgetcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
3601060SN/A{
3611060SN/A    int result = 0;
3621060SN/A    int index = 0;
3631060SN/A    Addr buf_ptr = p->getSyscallArg(tc, index);
3641060SN/A    unsigned long size = p->getSyscallArg(tc, index);
3651060SN/A    BufferArg buf(buf_ptr, size);
3661060SN/A
3671060SN/A    // Is current working directory defined?
3681060SN/A    string cwd = p->getcwd();
3691060SN/A    if (!cwd.empty()) {
3701060SN/A        if (cwd.length() >= size) {
3712292SN/A            // Buffer too small
3721060SN/A            return -ERANGE;
3731060SN/A        }
3741060SN/A        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
3752292SN/A        result = cwd.length();
3762733Sktlim@umich.edu    } else {
3772733Sktlim@umich.edu        if (getcwd((char *)buf.bufferPtr(), size)) {
3781060SN/A            result = strlen((char *)buf.bufferPtr());
3792348SN/A        } else {
3802292SN/A            result = -1;
3811060SN/A        }
3822292SN/A    }
3832292SN/A
3842292SN/A    buf.copyOut(tc->getMemProxy());
3852292SN/A
3862292SN/A    return (result == -1) ? -errno : result;
3872292SN/A}
3882292SN/A
3892292SN/ASyscallReturn
3902292SN/AreadlinkFunc(SyscallDesc *desc, int callnum, Process *process,
3912292SN/A             ThreadContext *tc)
3922292SN/A{
3936221Snate@binkert.org    return readlinkFunc(desc, callnum, process, tc, 0);
3942292SN/A}
3952292SN/A
3962292SN/ASyscallReturn
3972292SN/AreadlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
3982292SN/A             int index)
3992680Sktlim@umich.edu{
4002292SN/A    string path;
4019437SAndreas.Sandberg@ARM.com
4029437SAndreas.Sandberg@ARM.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
4039437SAndreas.Sandberg@ARM.com        return -EFAULT;
4049437SAndreas.Sandberg@ARM.com
4059437SAndreas.Sandberg@ARM.com    // Adjust path for current working directory
4069437SAndreas.Sandberg@ARM.com    path = p->fullPath(path);
4079437SAndreas.Sandberg@ARM.com
4089437SAndreas.Sandberg@ARM.com    Addr buf_ptr = p->getSyscallArg(tc, index);
4099437SAndreas.Sandberg@ARM.com    size_t bufsiz = p->getSyscallArg(tc, index);
4102292SN/A
4116221Snate@binkert.org    BufferArg buf(buf_ptr, bufsiz);
4122292SN/A
4139184Sandreas.hansson@arm.com    int result = -1;
4149184Sandreas.hansson@arm.com    if (path != "/proc/self/exe") {
4151060SN/A        result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
4169184Sandreas.hansson@arm.com    } else {
4179184Sandreas.hansson@arm.com        // Emulate readlink() called on '/proc/self/exe' should return the
4182292SN/A        // absolute path of the binary running in the simulated system (the
4199184Sandreas.hansson@arm.com        // Process' executable). It is possible that using this path in
4209184Sandreas.hansson@arm.com        // the simulated system will result in unexpected behavior if:
4211060SN/A        //  1) One binary runs another (e.g., -c time -o "my_binary"), and
4229184Sandreas.hansson@arm.com        //     called binary calls readlink().
4232292SN/A        //  2) The host's full path to the running benchmark changes from one
4241060SN/A        //     simulation to another. This can result in different simulated
4251060SN/A        //     performance since the simulated system will process the binary
4261060SN/A        //     path differently, even if the binary itself does not change.
4271060SN/A
4281060SN/A        // Get the absolute canonical path to the running application
4291060SN/A        char real_path[PATH_MAX];
4301060SN/A        char *check_real_path = realpath(p->progName(), real_path);
4311062SN/A        if (!check_real_path) {
4322292SN/A            fatal("readlink('/proc/self/exe') unable to resolve path to "
4332292SN/A                  "executable: %s", p->progName());
4342292SN/A        }
4352292SN/A        strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
4366221Snate@binkert.org        size_t real_path_len = strlen(real_path);
4372292SN/A        if (real_path_len > bufsiz) {
4382843Sktlim@umich.edu            // readlink will truncate the contents of the
4392843Sktlim@umich.edu            // path to ensure it is no more than bufsiz
4402348SN/A            result = bufsiz;
4412348SN/A        } else {
4422307SN/A            result = real_path_len;
4432307SN/A        }
4442348SN/A
4452348SN/A        // Issue a warning about potential unexpected results
4462348SN/A        warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
4479180Sandreas.hansson@arm.com                  "results in various settings.\n      Returning '%s'\n",
4482292SN/A                  (char*)buf.bufferPtr());
4493640Sktlim@umich.edu    }
4503640Sktlim@umich.edu
4513640Sktlim@umich.edu    buf.copyOut(tc->getMemProxy());
4527720Sgblack@eecs.umich.edu
4532348SN/A    return (result == -1) ? -errno : result;
4542348SN/A}
4557720Sgblack@eecs.umich.edu
4564636Sgblack@eecs.umich.eduSyscallReturn
4572292SN/AunlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
4582292SN/A{
4592292SN/A    return unlinkHelper(desc, num, p, tc, 0);
4607855SAli.Saidi@ARM.com}
4617855SAli.Saidi@ARM.com
4627855SAli.Saidi@ARM.comSyscallReturn
4634035Sktlim@umich.eduunlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
4644035Sktlim@umich.edu             int index)
4654035Sktlim@umich.edu{
4664035Sktlim@umich.edu    string path;
4674035Sktlim@umich.edu
4684035Sktlim@umich.edu    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
4694035Sktlim@umich.edu        return -EFAULT;
4704035Sktlim@umich.edu
4714035Sktlim@umich.edu    path = p->fullPath(path);
4724035Sktlim@umich.edu
4732292SN/A    int result = unlink(path.c_str());
4746221Snate@binkert.org    return (result == -1) ? -errno : result;
4752292SN/A}
4762292SN/A
4772292SN/ASyscallReturn
4782292SN/AlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
4798823Snilay@cs.wisc.edu{
4808823Snilay@cs.wisc.edu    string path;
4818823Snilay@cs.wisc.edu    string new_path;
4822348SN/A
4832301SN/A    int index = 0;
4842301SN/A    auto &virt_mem = tc->getMemProxy();
4852292SN/A    if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index)))
4862292SN/A        return -EFAULT;
4875999Snate@binkert.org    if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
4882292SN/A        return -EFAULT;
4892292SN/A
4902292SN/A    path = p->fullPath(path);
4915999Snate@binkert.org    new_path = p->fullPath(new_path);
4922292SN/A
4932292SN/A    int result = link(path.c_str(), new_path.c_str());
4942292SN/A    return (result == -1) ? -errno : result;
4955999Snate@binkert.org}
4962292SN/A
4975999Snate@binkert.orgSyscallReturn
4982292SN/AsymlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
4995999Snate@binkert.org{
5001062SN/A    string path;
5012316SN/A    string new_path;
5028834Satgutier@umich.edu
5038834Satgutier@umich.edu    int index = 0;
5048834Satgutier@umich.edu    auto &virt_mem = tc->getMemProxy();
5052316SN/A    if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index)))
5065999Snate@binkert.org        return -EFAULT;
5072316SN/A    if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
5085999Snate@binkert.org        return -EFAULT;
5092316SN/A
5105999Snate@binkert.org    path = p->fullPath(path);
5112316SN/A    new_path = p->fullPath(new_path);
5125999Snate@binkert.org
5132316SN/A    int result = symlink(path.c_str(), new_path.c_str());
5145999Snate@binkert.org    return (result == -1) ? -errno : result;
5157897Shestness@cs.utexas.edu}
5167897Shestness@cs.utexas.edu
5177897Shestness@cs.utexas.eduSyscallReturn
5187897Shestness@cs.utexas.edumkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
5197897Shestness@cs.utexas.edu{
5207897Shestness@cs.utexas.edu    string path;
5212301SN/A
5222348SN/A    int index = 0;
5235999Snate@binkert.org    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
5242348SN/A        return -EFAULT;
5255999Snate@binkert.org
5261060SN/A    // Adjust path for current working directory
5271060SN/A    path = p->fullPath(path);
5282292SN/A
529    mode_t mode = p->getSyscallArg(tc, index);
530
531    int result = mkdir(path.c_str(), mode);
532    return (result == -1) ? -errno : result;
533}
534
535SyscallReturn
536renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
537{
538    string old_name;
539
540    int index = 0;
541    if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index)))
542        return -EFAULT;
543
544    string new_name;
545
546    if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index)))
547        return -EFAULT;
548
549    // Adjust path for current working directory
550    old_name = p->fullPath(old_name);
551    new_name = p->fullPath(new_name);
552
553    int64_t result = rename(old_name.c_str(), new_name.c_str());
554    return (result == -1) ? -errno : result;
555}
556
557SyscallReturn
558truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
559{
560    string path;
561
562    int index = 0;
563    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
564        return -EFAULT;
565
566    off_t length = p->getSyscallArg(tc, index);
567
568    // Adjust path for current working directory
569    path = p->fullPath(path);
570
571    int result = truncate(path.c_str(), length);
572    return (result == -1) ? -errno : result;
573}
574
575SyscallReturn
576ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
577{
578    int index = 0;
579    int tgt_fd = p->getSyscallArg(tc, index);
580    off_t length = p->getSyscallArg(tc, index);
581
582    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
583    if (!ffdp)
584        return -EBADF;
585    int sim_fd = ffdp->getSimFD();
586
587    int result = ftruncate(sim_fd, length);
588    return (result == -1) ? -errno : result;
589}
590
591SyscallReturn
592truncate64Func(SyscallDesc *desc, int num,
593               Process *process, ThreadContext *tc)
594{
595    int index = 0;
596    string path;
597
598    if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index)))
599        return -EFAULT;
600
601    int64_t length = process->getSyscallArg(tc, index, 64);
602
603    // Adjust path for current working directory
604    path = process->fullPath(path);
605
606#if NO_STAT64
607    int result = truncate(path.c_str(), length);
608#else
609    int result = truncate64(path.c_str(), length);
610#endif
611    return (result == -1) ? -errno : result;
612}
613
614SyscallReturn
615ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
616{
617    int index = 0;
618    int tgt_fd = p->getSyscallArg(tc, index);
619    int64_t length = p->getSyscallArg(tc, index, 64);
620
621    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
622    if (!ffdp)
623        return -EBADF;
624    int sim_fd = ffdp->getSimFD();
625
626#if NO_STAT64
627    int result = ftruncate(sim_fd, length);
628#else
629    int result = ftruncate64(sim_fd, length);
630#endif
631    return (result == -1) ? -errno : result;
632}
633
634SyscallReturn
635umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
636{
637    // Letting the simulated program change the simulator's umask seems like
638    // a bad idea.  Compromise by just returning the current umask but not
639    // changing anything.
640    mode_t oldMask = umask(0);
641    umask(oldMask);
642    return (int)oldMask;
643}
644
645SyscallReturn
646chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
647{
648    string path;
649
650    int index = 0;
651    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
652        return -EFAULT;
653
654    /* XXX endianess */
655    uint32_t owner = p->getSyscallArg(tc, index);
656    uid_t hostOwner = owner;
657    uint32_t group = p->getSyscallArg(tc, index);
658    gid_t hostGroup = group;
659
660    // Adjust path for current working directory
661    path = p->fullPath(path);
662
663    int result = chown(path.c_str(), hostOwner, hostGroup);
664    return (result == -1) ? -errno : result;
665}
666
667SyscallReturn
668fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
669{
670    int index = 0;
671    int tgt_fd = p->getSyscallArg(tc, index);
672
673    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
674    if (!ffdp)
675        return -EBADF;
676    int sim_fd = ffdp->getSimFD();
677
678    /* XXX endianess */
679    uint32_t owner = p->getSyscallArg(tc, index);
680    uid_t hostOwner = owner;
681    uint32_t group = p->getSyscallArg(tc, index);
682    gid_t hostGroup = group;
683
684    int result = fchown(sim_fd, hostOwner, hostGroup);
685    return (result == -1) ? -errno : result;
686}
687
688/**
689 * FIXME: The file description is not shared among file descriptors created
690 * with dup. Really, it's difficult to maintain fields like file offset or
691 * flags since an update to such a field won't be reflected in the metadata
692 * for the fd entries that we maintain for checkpoint restoration.
693 */
694SyscallReturn
695dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
696{
697    int index = 0;
698    int tgt_fd = p->getSyscallArg(tc, index);
699
700    auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
701    if (!old_hbfdp)
702        return -EBADF;
703    int sim_fd = old_hbfdp->getSimFD();
704
705    int result = dup(sim_fd);
706    if (result == -1)
707        return -errno;
708
709    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone());
710    new_hbfdp->setSimFD(result);
711    new_hbfdp->setCOE(false);
712    return p->fds->allocFD(new_hbfdp);
713}
714
715SyscallReturn
716dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
717{
718    int index = 0;
719
720    int old_tgt_fd = p->getSyscallArg(tc, index);
721    auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]);
722    if (!old_hbp)
723        return -EBADF;
724    int old_sim_fd = old_hbp->getSimFD();
725
726    /**
727     * We need a valid host file descriptor number to be able to pass into
728     * the second parameter for dup2 (newfd), but we don't know what the
729     * viable numbers are; we execute the open call to retrieve one.
730     */
731    int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY));
732    if (res_fd == -1)
733        return -errno;
734
735    int new_tgt_fd = p->getSyscallArg(tc, index);
736    auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]);
737    if (new_hbp)
738        p->fds->closeFDEntry(new_tgt_fd);
739    new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone());
740    new_hbp->setSimFD(res_fd);
741    new_hbp->setCOE(false);
742
743    return p->fds->allocFD(new_hbp);
744}
745
746SyscallReturn
747fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
748{
749    int arg;
750    int index = 0;
751    int tgt_fd = p->getSyscallArg(tc, index);
752    int cmd = p->getSyscallArg(tc, index);
753
754    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
755    if (!hbfdp)
756        return -EBADF;
757    int sim_fd = hbfdp->getSimFD();
758
759    int coe = hbfdp->getCOE();
760
761    switch (cmd) {
762      case F_GETFD:
763        return coe & FD_CLOEXEC;
764
765      case F_SETFD: {
766        arg = p->getSyscallArg(tc, index);
767        arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false);
768        return 0;
769      }
770
771      // Rely on the host to maintain the file status flags for this file
772      // description rather than maintain it ourselves. Admittedly, this
773      // is suboptimal (and possibly error prone), but it is difficult to
774      // maintain the flags by tracking them across the different descriptors
775      // (that refer to this file description) caused by clone, dup, and
776      // subsequent fcntls.
777      case F_GETFL:
778      case F_SETFL: {
779        arg = p->getSyscallArg(tc, index);
780        int rv = fcntl(sim_fd, cmd, arg);
781        return (rv == -1) ? -errno : rv;
782      }
783
784      default:
785        warn("fcntl: unsupported command %d\n", cmd);
786        return 0;
787    }
788}
789
790SyscallReturn
791fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
792{
793    int index = 0;
794    int tgt_fd = p->getSyscallArg(tc, index);
795
796    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
797    if (!hbfdp)
798        return -EBADF;
799    int sim_fd = hbfdp->getSimFD();
800
801    int cmd = p->getSyscallArg(tc, index);
802    switch (cmd) {
803      case 33: //F_GETLK64
804        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
805        return -EMFILE;
806
807      case 34: // F_SETLK64
808      case 35: // F_SETLKW64
809        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
810             tgt_fd);
811        return -EMFILE;
812
813      default:
814        // not sure if this is totally valid, but we'll pass it through
815        // to the underlying OS
816        warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd);
817        return fcntl(sim_fd, cmd);
818    }
819}
820
821SyscallReturn
822pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
823         bool pseudoPipe)
824{
825    Addr tgt_addr = 0;
826    if (!pseudoPipe) {
827        int index = 0;
828        tgt_addr = p->getSyscallArg(tc, index);
829    }
830
831    int sim_fds[2], tgt_fds[2];
832
833    int pipe_retval = pipe(sim_fds);
834    if (pipe_retval == -1)
835        return -errno;
836
837    auto rend = PipeFDEntry::EndType::read;
838    auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
839    tgt_fds[0] = p->fds->allocFD(rpfd);
840
841    auto wend = PipeFDEntry::EndType::write;
842    auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
843    tgt_fds[1] = p->fds->allocFD(wpfd);
844
845    /**
846     * Now patch the read object to record the target file descriptor chosen
847     * as the write end of the pipe.
848     */
849    rpfd->setPipeReadSource(tgt_fds[1]);
850
851    /**
852     * Alpha Linux convention for pipe() is that fd[0] is returned as
853     * the return value of the function, and fd[1] is returned in r20.
854     */
855    if (pseudoPipe) {
856        tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
857        return tgt_fds[0];
858    }
859
860    /**
861     * Copy the target file descriptors into buffer space and then copy
862     * the buffer space back into the target address space.
863     */
864    BufferArg tgt_handle(tgt_addr, sizeof(int[2]));
865    int *buf_ptr = (int*)tgt_handle.bufferPtr();
866    buf_ptr[0] = tgt_fds[0];
867    buf_ptr[1] = tgt_fds[1];
868    tgt_handle.copyOut(tc->getMemProxy());
869    return 0;
870}
871
872SyscallReturn
873pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
874               ThreadContext *tc)
875{
876    return pipeImpl(desc, callnum, process, tc, true);
877}
878
879SyscallReturn
880pipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
881{
882    return pipeImpl(desc, callnum, process, tc, false);
883}
884
885SyscallReturn
886setpgidFunc(SyscallDesc *desc, int callnum, Process *process,
887            ThreadContext *tc)
888{
889    int index = 0;
890    int pid = process->getSyscallArg(tc, index);
891    int pgid = process->getSyscallArg(tc, index);
892
893    if (pgid < 0)
894        return -EINVAL;
895
896    if (pid == 0) {
897        process->setpgid(process->pid());
898        return 0;
899    }
900
901    Process *matched_ph = nullptr;
902    System *sysh = tc->getSystemPtr();
903
904    // Retrieves process pointer from active/suspended thread contexts.
905    for (int i = 0; i < sysh->numContexts(); i++) {
906        if (sysh->threadContexts[i]->status() != ThreadContext::Halted) {
907            Process *temp_h = sysh->threadContexts[i]->getProcessPtr();
908            Process *walk_ph = (Process*)temp_h;
909
910            if (walk_ph && walk_ph->pid() == process->pid())
911                matched_ph = walk_ph;
912        }
913    }
914
915    assert(matched_ph);
916    matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid);
917
918    return 0;
919}
920
921SyscallReturn
922getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
923                 ThreadContext *tc)
924{
925    // Make up a PID.  There's no interprocess communication in
926    // fake_syscall mode, so there's no way for a process to know it's
927    // not getting a unique value.
928
929    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
930    return process->pid();
931}
932
933
934SyscallReturn
935getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
936                 ThreadContext *tc)
937{
938    // Make up a UID and EUID... it shouldn't matter, and we want the
939    // simulation to be deterministic.
940
941    // EUID goes in r20.
942    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID
943    return process->uid(); // UID
944}
945
946
947SyscallReturn
948getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
949                 ThreadContext *tc)
950{
951    // Get current group ID.  EGID goes in r20.
952    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID
953    return process->gid();
954}
955
956
957SyscallReturn
958setuidFunc(SyscallDesc *desc, int callnum, Process *process,
959           ThreadContext *tc)
960{
961    // can't fathom why a benchmark would call this.
962    int index = 0;
963    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
964    return 0;
965}
966
967SyscallReturn
968getpidFunc(SyscallDesc *desc, int callnum, Process *process,
969           ThreadContext *tc)
970{
971    return process->tgid();
972}
973
974SyscallReturn
975gettidFunc(SyscallDesc *desc, int callnum, Process *process,
976           ThreadContext *tc)
977{
978    return process->pid();
979}
980
981SyscallReturn
982getppidFunc(SyscallDesc *desc, int callnum, Process *process,
983            ThreadContext *tc)
984{
985    return process->ppid();
986}
987
988SyscallReturn
989getuidFunc(SyscallDesc *desc, int callnum, Process *process,
990           ThreadContext *tc)
991{
992    return process->uid();              // UID
993}
994
995SyscallReturn
996geteuidFunc(SyscallDesc *desc, int callnum, Process *process,
997            ThreadContext *tc)
998{
999    return process->euid();             // UID
1000}
1001
1002SyscallReturn
1003getgidFunc(SyscallDesc *desc, int callnum, Process *process,
1004           ThreadContext *tc)
1005{
1006    return process->gid();
1007}
1008
1009SyscallReturn
1010getegidFunc(SyscallDesc *desc, int callnum, Process *process,
1011            ThreadContext *tc)
1012{
1013    return process->egid();
1014}
1015
1016SyscallReturn
1017fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1018{
1019#if NO_FALLOCATE
1020    warn("Host OS cannot support calls to fallocate. Ignoring syscall");
1021#else
1022    int index = 0;
1023    int tgt_fd = p->getSyscallArg(tc, index);
1024    int mode = p->getSyscallArg(tc, index);
1025    off_t offset = p->getSyscallArg(tc, index);
1026    off_t len = p->getSyscallArg(tc, index);
1027
1028    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1029    if (!ffdp)
1030        return -EBADF;
1031    int sim_fd = ffdp->getSimFD();
1032
1033    int result = fallocate(sim_fd, mode, offset, len);
1034    if (result < 0)
1035        return -errno;
1036#endif
1037    return 0;
1038}
1039
1040SyscallReturn
1041accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
1042           int index)
1043{
1044    string path;
1045    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1046        return -EFAULT;
1047
1048    // Adjust path for current working directory
1049    path = p->fullPath(path);
1050
1051    mode_t mode = p->getSyscallArg(tc, index);
1052
1053    int result = access(path.c_str(), mode);
1054    return (result == -1) ? -errno : result;
1055}
1056
1057SyscallReturn
1058accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1059{
1060    return accessFunc(desc, callnum, p, tc, 0);
1061}
1062
1063SyscallReturn
1064mknodFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1065{
1066    int index = 0;
1067    std::string path;
1068    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1069        return -EFAULT;
1070
1071    path = p->fullPath(path);
1072    mode_t mode = p->getSyscallArg(tc, index);
1073    dev_t dev = p->getSyscallArg(tc, index);
1074
1075    auto result = mknod(path.c_str(), mode, dev);
1076    return (result == -1) ? -errno : result;
1077}
1078
1079SyscallReturn
1080chdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1081{
1082    int index = 0;
1083    std::string path;
1084    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1085        return -EFAULT;
1086
1087    path = p->fullPath(path);
1088
1089    auto result = chdir(path.c_str());
1090    return (result == -1) ? -errno : result;
1091}
1092
1093SyscallReturn
1094rmdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1095{
1096    int index = 0;
1097    std::string path;
1098    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
1099        return -EFAULT;
1100
1101    path = p->fullPath(path);
1102
1103    auto result = rmdir(path.c_str());
1104    return (result == -1) ? -errno : result;
1105}
1106
1107#if defined(SYS_getdents) || defined(SYS_getdents64)
1108template<typename DE, int SYS_NUM>
1109static SyscallReturn
1110getdentsImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1111{
1112    int index = 0;
1113    int tgt_fd = p->getSyscallArg(tc, index);
1114    Addr buf_ptr = p->getSyscallArg(tc, index);
1115    unsigned count = p->getSyscallArg(tc, index);
1116
1117    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1118    if (!hbfdp)
1119        return -EBADF;
1120    int sim_fd = hbfdp->getSimFD();
1121
1122    BufferArg buf_arg(buf_ptr, count);
1123    auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count);
1124
1125    if (status == -1)
1126        return -errno;
1127
1128    unsigned traversed = 0;
1129    while (traversed < status) {
1130        DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed);
1131
1132        auto host_reclen = buffer->d_reclen;
1133
1134        /**
1135         * Convert the byte ordering from the host to the target before
1136         * passing the data back into the target's address space to preserve
1137         * endianness.
1138         */
1139        buffer->d_ino = htog(buffer->d_ino);
1140        buffer->d_off = htog(buffer->d_off);
1141        buffer->d_reclen = htog(buffer->d_reclen);
1142
1143        traversed += host_reclen;
1144    }
1145
1146    buf_arg.copyOut(tc->getMemProxy());
1147    return status;
1148}
1149#endif
1150
1151#if defined(SYS_getdents)
1152SyscallReturn
1153getdentsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1154{
1155    typedef struct linux_dirent {
1156        unsigned long d_ino;
1157        unsigned long d_off;
1158        unsigned short d_reclen;
1159        char dname[];
1160    } LinDent;
1161
1162    return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, p, tc);
1163}
1164#endif
1165
1166#if defined(SYS_getdents64)
1167SyscallReturn
1168getdents64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1169{
1170    typedef struct linux_dirent64 {
1171        ino64_t d_ino;
1172        off64_t d_off;
1173        unsigned short d_reclen;
1174        char dname[];
1175    } LinDent64;
1176
1177    return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, p, tc);
1178}
1179#endif
1180
1181SyscallReturn
1182shutdownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1183{
1184    int index = 0;
1185    int tgt_fd = p->getSyscallArg(tc, index);
1186    int how = p->getSyscallArg(tc, index);
1187
1188    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1189    if (!sfdp)
1190        return -EBADF;
1191    int sim_fd = sfdp->getSimFD();
1192
1193    int retval = shutdown(sim_fd, how);
1194
1195    return (retval == -1) ? -errno : retval;
1196}
1197
1198SyscallReturn
1199bindFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1200{
1201    int index = 0;
1202    int tgt_fd = p->getSyscallArg(tc, index);
1203    Addr buf_ptr = p->getSyscallArg(tc, index);
1204    int addrlen = p->getSyscallArg(tc, index);
1205
1206    BufferArg bufSock(buf_ptr, addrlen);
1207    bufSock.copyIn(tc->getMemProxy());
1208
1209    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1210    if (!sfdp)
1211        return -EBADF;
1212    int sim_fd = sfdp->getSimFD();
1213
1214    int status = ::bind(sim_fd,
1215                        (struct sockaddr *)bufSock.bufferPtr(),
1216                        addrlen);
1217
1218    return (status == -1) ? -errno : status;
1219}
1220
1221SyscallReturn
1222listenFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1223{
1224    int index = 0;
1225    int tgt_fd = p->getSyscallArg(tc, index);
1226    int backlog = p->getSyscallArg(tc, index);
1227
1228    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1229    if (!sfdp)
1230        return -EBADF;
1231    int sim_fd = sfdp->getSimFD();
1232
1233    int status = listen(sim_fd, backlog);
1234
1235    return (status == -1) ? -errno : status;
1236}
1237
1238SyscallReturn
1239connectFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1240{
1241    int index = 0;
1242    int tgt_fd = p->getSyscallArg(tc, index);
1243    Addr buf_ptr = p->getSyscallArg(tc, index);
1244    int addrlen = p->getSyscallArg(tc, index);
1245
1246    BufferArg addr(buf_ptr, addrlen);
1247    addr.copyIn(tc->getMemProxy());
1248
1249    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1250    if (!sfdp)
1251        return -EBADF;
1252    int sim_fd = sfdp->getSimFD();
1253
1254    int status = connect(sim_fd,
1255                         (struct sockaddr *)addr.bufferPtr(),
1256                         (socklen_t)addrlen);
1257
1258    return (status == -1) ? -errno : status;
1259}
1260
1261SyscallReturn
1262recvfromFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1263{
1264    int index = 0;
1265    int tgt_fd = p->getSyscallArg(tc, index);
1266    Addr bufrPtr = p->getSyscallArg(tc, index);
1267    size_t bufrLen = p->getSyscallArg(tc, index);
1268    int flags = p->getSyscallArg(tc, index);
1269    Addr addrPtr = p->getSyscallArg(tc, index);
1270    Addr addrlenPtr = p->getSyscallArg(tc, index);
1271
1272    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1273    if (!sfdp)
1274        return -EBADF;
1275    int sim_fd = sfdp->getSimFD();
1276
1277    // Reserve buffer space.
1278    BufferArg bufrBuf(bufrPtr, bufrLen);
1279
1280    // Get address length.
1281    socklen_t addrLen = 0;
1282    if (addrlenPtr != 0) {
1283        // Read address length parameter.
1284        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1285        addrlenBuf.copyIn(tc->getMemProxy());
1286        addrLen = *((socklen_t *)addrlenBuf.bufferPtr());
1287    }
1288
1289    struct sockaddr sa, *sap = NULL;
1290    if (addrLen != 0) {
1291        BufferArg addrBuf(addrPtr, addrLen);
1292        addrBuf.copyIn(tc->getMemProxy());
1293        memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(),
1294               sizeof(struct sockaddr));
1295        sap = &sa;
1296    }
1297
1298    ssize_t recvd_size = recvfrom(sim_fd,
1299                                  (void *)bufrBuf.bufferPtr(),
1300                                  bufrLen, flags, sap, (socklen_t *)&addrLen);
1301
1302    if (recvd_size == -1)
1303        return -errno;
1304
1305    // Pass the received data out.
1306    bufrBuf.copyOut(tc->getMemProxy());
1307
1308    // Copy address to addrPtr and pass it on.
1309    if (sap != NULL) {
1310        BufferArg addrBuf(addrPtr, addrLen);
1311        memcpy(addrBuf.bufferPtr(), sap, sizeof(sa));
1312        addrBuf.copyOut(tc->getMemProxy());
1313    }
1314
1315    // Copy len to addrlenPtr and pass it on.
1316    if (addrLen != 0) {
1317        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
1318        *(socklen_t *)addrlenBuf.bufferPtr() = addrLen;
1319        addrlenBuf.copyOut(tc->getMemProxy());
1320    }
1321
1322    return recvd_size;
1323}
1324
1325SyscallReturn
1326sendtoFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1327{
1328    int index = 0;
1329    int tgt_fd = p->getSyscallArg(tc, index);
1330    Addr bufrPtr = p->getSyscallArg(tc, index);
1331    size_t bufrLen = p->getSyscallArg(tc, index);
1332    int flags = p->getSyscallArg(tc, index);
1333    Addr addrPtr = p->getSyscallArg(tc, index);
1334    socklen_t addrLen = p->getSyscallArg(tc, index);
1335
1336    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1337    if (!sfdp)
1338        return -EBADF;
1339    int sim_fd = sfdp->getSimFD();
1340
1341    // Reserve buffer space.
1342    BufferArg bufrBuf(bufrPtr, bufrLen);
1343    bufrBuf.copyIn(tc->getMemProxy());
1344
1345    struct sockaddr sa, *sap = nullptr;
1346    memset(&sa, 0, sizeof(sockaddr));
1347    if (addrLen != 0) {
1348        BufferArg addrBuf(addrPtr, addrLen);
1349        addrBuf.copyIn(tc->getMemProxy());
1350        memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen);
1351        sap = &sa;
1352    }
1353
1354    ssize_t sent_size = sendto(sim_fd,
1355                               (void *)bufrBuf.bufferPtr(),
1356                               bufrLen, flags, sap, (socklen_t)addrLen);
1357
1358    return (sent_size == -1) ? -errno : sent_size;
1359}
1360
1361SyscallReturn
1362recvmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1363{
1364    int index = 0;
1365    int tgt_fd = p->getSyscallArg(tc, index);
1366    Addr msgPtr = p->getSyscallArg(tc, index);
1367    int flags = 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     /**
1375      *  struct msghdr {
1376      *     void         *msg_name;       // optional address
1377      *    socklen_t     msg_namelen;    // size of address
1378      *    struct iovec *msg_iov;        // iovec array
1379      *    size_t        msg_iovlen;     // number entries in msg_iov
1380      *    i                             // entries correspond to buffer
1381      *    void         *msg_control;    // ancillary data
1382      *    size_t        msg_controllen; // ancillary data buffer len
1383      *    int           msg_flags;      // flags on received message
1384      *  };
1385      *
1386      *  struct iovec {
1387      *    void  *iov_base;              // starting address
1388      *    size_t iov_len;               // number of bytes to transfer
1389      *  };
1390      */
1391
1392    /**
1393     * The plan with this system call is to replace all of the pointers in the
1394     * structure and the substructure with BufferArg class pointers. We will
1395     * copy every field from the structures into our BufferArg classes.
1396     */
1397    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1398    msgBuf.copyIn(tc->getMemProxy());
1399    struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr();
1400
1401    /**
1402     * We will use these address place holders to retain the pointers which
1403     * we are going to replace with our own buffers in our simulator address
1404     * space.
1405     */
1406    Addr msg_name_phold = 0;
1407    Addr msg_iov_phold = 0;
1408    Addr iovec_base_phold[msgHdr->msg_iovlen];
1409    Addr msg_control_phold = 0;
1410
1411    /**
1412     * Record msg_name pointer then replace with buffer pointer.
1413     */
1414    BufferArg *nameBuf = NULL;
1415    if (msgHdr->msg_name) {
1416        /*1*/msg_name_phold = (Addr)msgHdr->msg_name;
1417        /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen);
1418        /*3*/nameBuf->copyIn(tc->getMemProxy());
1419        /*4*/msgHdr->msg_name = nameBuf->bufferPtr();
1420    }
1421
1422    /**
1423     * Record msg_iov pointer then replace with buffer pointer. Also, setup
1424     * an array of buffer pointers for the iovec structs record and replace
1425     * their pointers with buffer pointers.
1426     */
1427    BufferArg *iovBuf = NULL;
1428    BufferArg *iovecBuf[msgHdr->msg_iovlen];
1429    for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1430        iovec_base_phold[i] = 0;
1431        iovecBuf[i] = NULL;
1432    }
1433
1434    if (msgHdr->msg_iov) {
1435        /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov;
1436        /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen *
1437                                    sizeof(struct iovec));
1438        /*3*/iovBuf->copyIn(tc->getMemProxy());
1439        for (int i = 0; i < msgHdr->msg_iovlen; i++) {
1440            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1441                /*1*/iovec_base_phold[i] =
1442                     (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base;
1443                /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i],
1444                     ((struct iovec *)iovBuf->bufferPtr())[i].iov_len);
1445                /*3*/iovecBuf[i]->copyIn(tc->getMemProxy());
1446                /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1447                     iovecBuf[i]->bufferPtr();
1448            }
1449        }
1450        /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr();
1451    }
1452
1453    /**
1454     * Record msg_control pointer then replace with buffer pointer.
1455     */
1456    BufferArg *controlBuf = NULL;
1457    if (msgHdr->msg_control) {
1458        /*1*/msg_control_phold = (Addr)msgHdr->msg_control;
1459        /*2*/controlBuf = new BufferArg(msg_control_phold,
1460                                        CMSG_ALIGN(msgHdr->msg_controllen));
1461        /*3*/controlBuf->copyIn(tc->getMemProxy());
1462        /*4*/msgHdr->msg_control = controlBuf->bufferPtr();
1463    }
1464
1465    ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags);
1466
1467    if (recvd_size < 0)
1468        return -errno;
1469
1470    if (msgHdr->msg_name) {
1471        nameBuf->copyOut(tc->getMemProxy());
1472        delete(nameBuf);
1473        msgHdr->msg_name = (void *)msg_name_phold;
1474    }
1475
1476    if (msgHdr->msg_iov) {
1477        for (int i = 0; i< msgHdr->msg_iovlen; i++) {
1478            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
1479                iovecBuf[i]->copyOut(tc->getMemProxy());
1480                delete iovecBuf[i];
1481                ((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
1482                (void *)iovec_base_phold[i];
1483            }
1484        }
1485        iovBuf->copyOut(tc->getMemProxy());
1486        delete iovBuf;
1487        msgHdr->msg_iov = (struct iovec *)msg_iov_phold;
1488    }
1489
1490    if (msgHdr->msg_control) {
1491        controlBuf->copyOut(tc->getMemProxy());
1492        delete(controlBuf);
1493        msgHdr->msg_control = (void *)msg_control_phold;
1494    }
1495
1496    msgBuf.copyOut(tc->getMemProxy());
1497
1498    return recvd_size;
1499}
1500
1501SyscallReturn
1502sendmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1503{
1504    int index = 0;
1505    int tgt_fd = p->getSyscallArg(tc, index);
1506    Addr msgPtr = p->getSyscallArg(tc, index);
1507    int flags = p->getSyscallArg(tc, index);
1508
1509    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1510    if (!sfdp)
1511        return -EBADF;
1512    int sim_fd = sfdp->getSimFD();
1513
1514    /**
1515     * Reserve buffer space.
1516     */
1517    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
1518    msgBuf.copyIn(tc->getMemProxy());
1519    struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr());
1520
1521    /**
1522     * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
1523     * recvmsg without a buffer.
1524     */
1525    struct iovec *iovPtr = msgHdr.msg_iov;
1526    BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen);
1527    iovBuf.copyIn(tc->getMemProxy());
1528    struct iovec *iov = (struct iovec *)iovBuf.bufferPtr();
1529    msgHdr.msg_iov = iov;
1530
1531    /**
1532     * Cannot instantiate buffers till inside the loop.
1533     * Create array to hold buffer addresses, to be used during copyIn of
1534     * send data.
1535     */
1536    BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen
1537                                                   * sizeof(BufferArg *));
1538
1539    /**
1540     * Iterate through the iovec structures:
1541     * Get the base buffer addreses, reserve iov_len amount of space for each.
1542     * Put the buf address into the bufferArray for later retrieval.
1543     */
1544    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1545        Addr basePtr = (Addr) iov[iovIndex].iov_base;
1546        bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len);
1547        bufferArray[iovIndex]->copyIn(tc->getMemProxy());
1548        iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr();
1549    }
1550
1551    ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags);
1552    int local_errno = errno;
1553
1554    /**
1555     * Free dynamically allocated memory.
1556     */
1557    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
1558        BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex];
1559        delete(baseBuf);
1560    }
1561
1562    /**
1563     * Malloced above.
1564     */
1565    free(bufferArray);
1566
1567    return (sent_size < 0) ? -local_errno : sent_size;
1568}
1569
1570SyscallReturn
1571getsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1572{
1573    // union of all possible return value types from getsockopt
1574    union val {
1575        int i_val;
1576        long l_val;
1577        struct linger linger_val;
1578        struct timeval timeval_val;
1579    } val;
1580
1581    int index = 0;
1582    int tgt_fd = p->getSyscallArg(tc, index);
1583    int level = p->getSyscallArg(tc, index);
1584    int optname = p->getSyscallArg(tc, index);
1585    Addr valPtr = p->getSyscallArg(tc, index);
1586    Addr lenPtr = p->getSyscallArg(tc, index);
1587
1588    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1589    if (!sfdp)
1590        return -EBADF;
1591    int sim_fd = sfdp->getSimFD();
1592
1593    socklen_t len = sizeof(val);
1594    int status = getsockopt(sim_fd, level, optname, &val, &len);
1595
1596    if (status == -1)
1597        return -errno;
1598
1599    // copy val to valPtr and pass it on
1600    BufferArg valBuf(valPtr, sizeof(val));
1601    memcpy(valBuf.bufferPtr(), &val, sizeof(val));
1602    valBuf.copyOut(tc->getMemProxy());
1603
1604    // copy len to lenPtr and pass  it on
1605    BufferArg lenBuf(lenPtr, sizeof(len));
1606    memcpy(lenBuf.bufferPtr(), &len, sizeof(len));
1607    lenBuf.copyOut(tc->getMemProxy());
1608
1609    return status;
1610}
1611
1612SyscallReturn
1613getsocknameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1614{
1615    int index = 0;
1616    int tgt_fd = p->getSyscallArg(tc, index);
1617    Addr addrPtr = p->getSyscallArg(tc, index);
1618    Addr lenPtr = p->getSyscallArg(tc, index);
1619
1620    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1621    if (!sfdp)
1622        return -EBADF;
1623    int sim_fd = sfdp->getSimFD();
1624
1625    // lenPtr is an in-out paramenter:
1626    // sending the address length in, conveying the final length out
1627
1628    // Read in the value of len from the passed pointer.
1629    BufferArg lenBuf(lenPtr, sizeof(socklen_t));
1630    lenBuf.copyIn(tc->getMemProxy());
1631    socklen_t len = *(socklen_t *)lenBuf.bufferPtr();
1632
1633    struct sockaddr sa;
1634    int status = getsockname(sim_fd, &sa, &len);
1635
1636    if (status == -1)
1637        return -errno;
1638
1639    // Copy address to addrPtr and pass it on.
1640    BufferArg addrBuf(addrPtr, sizeof(sa));
1641    memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa));
1642    addrBuf.copyOut(tc->getMemProxy());
1643
1644    // Copy len to lenPtr and pass  it on.
1645    *(socklen_t *)lenBuf.bufferPtr() = len;
1646    lenBuf.copyOut(tc->getMemProxy());
1647
1648    return status;
1649}
1650
1651SyscallReturn
1652getpeernameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1653{
1654    int index = 0;
1655    int tgt_fd = p->getSyscallArg(tc, index);
1656    Addr sockAddrPtr = p->getSyscallArg(tc, index);
1657    Addr addrlenPtr = p->getSyscallArg(tc, index);
1658
1659    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1660    if (!sfdp)
1661        return -EBADF;
1662    int sim_fd = sfdp->getSimFD();
1663
1664    BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned));
1665    bufAddrlen.copyIn(tc->getMemProxy());
1666    BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr());
1667
1668    int retval = getpeername(sim_fd,
1669                             (struct sockaddr *)bufSock.bufferPtr(),
1670                             (unsigned *)bufAddrlen.bufferPtr());
1671
1672    if (retval != -1) {
1673        bufSock.copyOut(tc->getMemProxy());
1674        bufAddrlen.copyOut(tc->getMemProxy());
1675    }
1676
1677    return (retval == -1) ? -errno : retval;
1678}
1679
1680SyscallReturn
1681setsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1682{
1683    int index = 0;
1684    int tgt_fd = p->getSyscallArg(tc, index);
1685    int level = p->getSyscallArg(tc, index);
1686    int optname = p->getSyscallArg(tc, index);
1687    Addr valPtr = p->getSyscallArg(tc, index);
1688    socklen_t len = p->getSyscallArg(tc, index);
1689
1690    BufferArg valBuf(valPtr, len);
1691    valBuf.copyIn(tc->getMemProxy());
1692
1693    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
1694    if (!sfdp)
1695        return -EBADF;
1696    int sim_fd = sfdp->getSimFD();
1697
1698    int status = setsockopt(sim_fd, level, optname,
1699                            (struct sockaddr *)valBuf.bufferPtr(), len);
1700
1701    return (status == -1) ? -errno : status;
1702}
1703
1704