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