syscall_emul.cc revision 14124
14483Sgblack@eecs.umich.edu/* 24483Sgblack@eecs.umich.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan 34483Sgblack@eecs.umich.edu * All rights reserved. 44483Sgblack@eecs.umich.edu * 54483Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 64483Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 74483Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 84483Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 94483Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 104483Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 114483Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 124483Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 134483Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 144483Sgblack@eecs.umich.edu * this software without specific prior written permission. 154483Sgblack@eecs.umich.edu * 164483Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 174483Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 184483Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 194483Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 204483Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 214483Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 224483Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234483Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244483Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254483Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 264483Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274483Sgblack@eecs.umich.edu * 284483Sgblack@eecs.umich.edu * Authors: Steve Reinhardt 294483Sgblack@eecs.umich.edu * Ali Saidi 304483Sgblack@eecs.umich.edu */ 314483Sgblack@eecs.umich.edu 324483Sgblack@eecs.umich.edu#include "sim/syscall_emul.hh" 334483Sgblack@eecs.umich.edu 344483Sgblack@eecs.umich.edu#include <fcntl.h> 354483Sgblack@eecs.umich.edu#include <sys/syscall.h> 364483Sgblack@eecs.umich.edu#include <unistd.h> 374483Sgblack@eecs.umich.edu 384483Sgblack@eecs.umich.edu#include <csignal> 394483Sgblack@eecs.umich.edu#include <iostream> 404483Sgblack@eecs.umich.edu#include <mutex> 414483Sgblack@eecs.umich.edu#include <string> 424483Sgblack@eecs.umich.edu 434483Sgblack@eecs.umich.edu#include "arch/utility.hh" 444483Sgblack@eecs.umich.edu#include "base/chunk_generator.hh" 454483Sgblack@eecs.umich.edu#include "base/trace.hh" 464483Sgblack@eecs.umich.edu#include "config/the_isa.hh" 474483Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 484483Sgblack@eecs.umich.edu#include "dev/net/dist_iface.hh" 494483Sgblack@eecs.umich.edu#include "mem/page_table.hh" 504483Sgblack@eecs.umich.edu#include "sim/byteswap.hh" 514483Sgblack@eecs.umich.edu#include "sim/process.hh" 524483Sgblack@eecs.umich.edu#include "sim/sim_exit.hh" 534483Sgblack@eecs.umich.edu#include "sim/syscall_debug_macros.hh" 544483Sgblack@eecs.umich.edu#include "sim/syscall_desc.hh" 554483Sgblack@eecs.umich.edu#include "sim/system.hh" 564483Sgblack@eecs.umich.edu 574483Sgblack@eecs.umich.eduusing namespace std; 584483Sgblack@eecs.umich.eduusing namespace TheISA; 594483Sgblack@eecs.umich.edu 604483Sgblack@eecs.umich.eduvoid 614483Sgblack@eecs.umich.eduwarnUnsupportedOS(std::string syscall_name) 624483Sgblack@eecs.umich.edu{ 634483Sgblack@eecs.umich.edu warn("Cannot invoke %s on host operating system.", syscall_name); 644483Sgblack@eecs.umich.edu} 654483Sgblack@eecs.umich.edu 664483Sgblack@eecs.umich.eduSyscallReturn 674507Sgblack@eecs.umich.eduunimplementedFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 684483Sgblack@eecs.umich.edu{ 694483Sgblack@eecs.umich.edu fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum); 704507Sgblack@eecs.umich.edu 714507Sgblack@eecs.umich.edu return 1; 724507Sgblack@eecs.umich.edu} 734507Sgblack@eecs.umich.edu 744507Sgblack@eecs.umich.edu 754508Sgblack@eecs.umich.eduSyscallReturn 764508Sgblack@eecs.umich.eduignoreFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 774508Sgblack@eecs.umich.edu{ 784483Sgblack@eecs.umich.edu if (desc->needWarning()) { 794483Sgblack@eecs.umich.edu warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ? 804483Sgblack@eecs.umich.edu "\n (further warnings will be suppressed)" : ""); 814483Sgblack@eecs.umich.edu } 824483Sgblack@eecs.umich.edu 834483Sgblack@eecs.umich.edu return 0; 844483Sgblack@eecs.umich.edu} 854483Sgblack@eecs.umich.edu 864483Sgblack@eecs.umich.edustatic void 874483Sgblack@eecs.umich.eduexitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid) 884483Sgblack@eecs.umich.edu{ 894483Sgblack@eecs.umich.edu // Clear value at address pointed to by thread's childClearTID field. 904483Sgblack@eecs.umich.edu BufferArg ctidBuf(addr, sizeof(long)); 914483Sgblack@eecs.umich.edu long *ctid = (long *)ctidBuf.bufferPtr(); 924483Sgblack@eecs.umich.edu *ctid = 0; 934483Sgblack@eecs.umich.edu ctidBuf.copyOut(tc->getVirtProxy()); 944483Sgblack@eecs.umich.edu 954483Sgblack@eecs.umich.edu FutexMap &futex_map = tc->getSystemPtr()->futexMap; 964483Sgblack@eecs.umich.edu // Wake one of the waiting threads. 974483Sgblack@eecs.umich.edu futex_map.wakeup(addr, tgid, 1); 984483Sgblack@eecs.umich.edu} 994483Sgblack@eecs.umich.edu 1004483Sgblack@eecs.umich.edustatic SyscallReturn 1014483Sgblack@eecs.umich.eduexitImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool group) 1024503Sgblack@eecs.umich.edu{ 1034483Sgblack@eecs.umich.edu int index = 0; 1044483Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 1054483Sgblack@eecs.umich.edu int status = p->getSyscallArg(tc, index); 1064483Sgblack@eecs.umich.edu 1074483Sgblack@eecs.umich.edu System *sys = tc->getSystemPtr(); 1084483Sgblack@eecs.umich.edu 1094483Sgblack@eecs.umich.edu if (group) 1104483Sgblack@eecs.umich.edu *p->exitGroup = true; 1114483Sgblack@eecs.umich.edu 1124483Sgblack@eecs.umich.edu if (p->childClearTID) 1134483Sgblack@eecs.umich.edu exitFutexWake(tc, p->childClearTID, p->tgid()); 1144483Sgblack@eecs.umich.edu 1154483Sgblack@eecs.umich.edu bool last_thread = true; 1164483Sgblack@eecs.umich.edu Process *parent = nullptr, *tg_lead = nullptr; 1174483Sgblack@eecs.umich.edu for (int i = 0; last_thread && i < sys->numContexts(); i++) { 1184483Sgblack@eecs.umich.edu Process *walk; 1194483Sgblack@eecs.umich.edu if (!(walk = sys->threadContexts[i]->getProcessPtr())) 1204483Sgblack@eecs.umich.edu continue; 1214483Sgblack@eecs.umich.edu 1224483Sgblack@eecs.umich.edu /** 1234483Sgblack@eecs.umich.edu * Threads in a thread group require special handing. For instance, 1244483Sgblack@eecs.umich.edu * we send the SIGCHLD signal so that it appears that it came from 1254483Sgblack@eecs.umich.edu * the head of the group. We also only delete file descriptors if 1264483Sgblack@eecs.umich.edu * we are the last thread in the thread group. 1274483Sgblack@eecs.umich.edu */ 1284483Sgblack@eecs.umich.edu if (walk->pid() == p->tgid()) 1294483Sgblack@eecs.umich.edu tg_lead = walk; 1304613Sgblack@eecs.umich.edu 1314613Sgblack@eecs.umich.edu if ((sys->threadContexts[i]->status() != ThreadContext::Halted) && 1324613Sgblack@eecs.umich.edu (sys->threadContexts[i]->status() != ThreadContext::Halting) && 1334613Sgblack@eecs.umich.edu (walk != p)) { 1344483Sgblack@eecs.umich.edu /** 1354613Sgblack@eecs.umich.edu * Check if we share thread group with the pointer; this denotes 1364613Sgblack@eecs.umich.edu * that we are not the last thread active in the thread group. 1374483Sgblack@eecs.umich.edu * Note that setting this to false also prevents further 1384591Sgblack@eecs.umich.edu * iterations of the loop. 1394591Sgblack@eecs.umich.edu */ 1404483Sgblack@eecs.umich.edu if (walk->tgid() == p->tgid()) { 1414483Sgblack@eecs.umich.edu /** 1424483Sgblack@eecs.umich.edu * If p is trying to exit_group and both walk and p are in 1434483Sgblack@eecs.umich.edu * the same thread group (i.e., sharing the same tgid), 1444483Sgblack@eecs.umich.edu * we need to halt walk's thread context. After all threads 1454483Sgblack@eecs.umich.edu * except p are halted, p becomes the last thread in the 1464483Sgblack@eecs.umich.edu * group. 1474483Sgblack@eecs.umich.edu * 1484483Sgblack@eecs.umich.edu * If p is not doing exit_group and there exists another 1494483Sgblack@eecs.umich.edu * active thread context in the group, last_thread is 1504483Sgblack@eecs.umich.edu * set to false to prevent the parent thread from killing 1514613Sgblack@eecs.umich.edu * all threads in the group. 1524613Sgblack@eecs.umich.edu */ 1534613Sgblack@eecs.umich.edu if (*(p->exitGroup)) { 1544613Sgblack@eecs.umich.edu sys->threadContexts[i]->halt(); 1554483Sgblack@eecs.umich.edu } else { 1564613Sgblack@eecs.umich.edu last_thread = false; 1574613Sgblack@eecs.umich.edu } 1584483Sgblack@eecs.umich.edu } 1594483Sgblack@eecs.umich.edu 1604483Sgblack@eecs.umich.edu /** 1614483Sgblack@eecs.umich.edu * A corner case exists which involves execve(). After execve(), 1624483Sgblack@eecs.umich.edu * the execve will enable SIGCHLD in the process. The problem 1634483Sgblack@eecs.umich.edu * occurs when the exiting process is the root process in the 1644483Sgblack@eecs.umich.edu * system; there is no parent to receive the signal. We obviate 1654483Sgblack@eecs.umich.edu * this problem by setting the root process' ppid to zero in the 1664483Sgblack@eecs.umich.edu * Python configuration files. We really should handle the 1674483Sgblack@eecs.umich.edu * root/execve specific case more gracefully. 1684483Sgblack@eecs.umich.edu */ 1694483Sgblack@eecs.umich.edu if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid())) 1704483Sgblack@eecs.umich.edu parent = walk; 1714483Sgblack@eecs.umich.edu } 1724483Sgblack@eecs.umich.edu } 1734483Sgblack@eecs.umich.edu 1744483Sgblack@eecs.umich.edu if (last_thread) { 1754483Sgblack@eecs.umich.edu if (parent) { 1764483Sgblack@eecs.umich.edu assert(tg_lead); 1774483Sgblack@eecs.umich.edu sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD)); 1784483Sgblack@eecs.umich.edu } 1794483Sgblack@eecs.umich.edu 1804483Sgblack@eecs.umich.edu /** 1814483Sgblack@eecs.umich.edu * Run though FD array of the exiting process and close all file 1824483Sgblack@eecs.umich.edu * descriptors except for the standard file descriptors. 1834483Sgblack@eecs.umich.edu * (The standard file descriptors are shared with gem5.) 1844483Sgblack@eecs.umich.edu */ 1854483Sgblack@eecs.umich.edu for (int i = 0; i < p->fds->getSize(); i++) { 1864483Sgblack@eecs.umich.edu if ((*p->fds)[i]) 1874483Sgblack@eecs.umich.edu p->fds->closeFDEntry(i); 1884483Sgblack@eecs.umich.edu } 1894483Sgblack@eecs.umich.edu } 1904483Sgblack@eecs.umich.edu 1914483Sgblack@eecs.umich.edu tc->halt(); 1924483Sgblack@eecs.umich.edu 1934483Sgblack@eecs.umich.edu /** 1944483Sgblack@eecs.umich.edu * check to see if there is no more active thread in the system. If so, 1954483Sgblack@eecs.umich.edu * exit the simulation loop 1964483Sgblack@eecs.umich.edu */ 1974483Sgblack@eecs.umich.edu int activeContexts = 0; 1984483Sgblack@eecs.umich.edu for (auto &system: sys->systemList) 1994483Sgblack@eecs.umich.edu activeContexts += system->numRunningContexts(); 2004483Sgblack@eecs.umich.edu 2014483Sgblack@eecs.umich.edu if (activeContexts == 0) { 2024483Sgblack@eecs.umich.edu /** 2034483Sgblack@eecs.umich.edu * Even though we are terminating the final thread context, dist-gem5 2044483Sgblack@eecs.umich.edu * requires the simulation to remain active and provide 2054483Sgblack@eecs.umich.edu * synchronization messages to the switch process. So we just halt 2064483Sgblack@eecs.umich.edu * the last thread context and return. The simulation will be 2074483Sgblack@eecs.umich.edu * terminated by dist-gem5 in a coordinated manner once all nodes 2084483Sgblack@eecs.umich.edu * have signaled their readiness to exit. For non dist-gem5 2094483Sgblack@eecs.umich.edu * simulations, readyToExit() always returns true. 2104512Sgblack@eecs.umich.edu */ 2114502Sgblack@eecs.umich.edu if (!DistIface::readyToExit(0)) { 2124502Sgblack@eecs.umich.edu return status; 2134502Sgblack@eecs.umich.edu } 2144502Sgblack@eecs.umich.edu 2154502Sgblack@eecs.umich.edu exitSimLoop("exiting with last active thread context", status & 0xff); 2164502Sgblack@eecs.umich.edu return status; 2174512Sgblack@eecs.umich.edu } 2184512Sgblack@eecs.umich.edu 2194512Sgblack@eecs.umich.edu return status; 2204483Sgblack@eecs.umich.edu} 2214483Sgblack@eecs.umich.edu 2224483Sgblack@eecs.umich.eduSyscallReturn 2234483Sgblack@eecs.umich.eduexitFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2244483Sgblack@eecs.umich.edu{ 2254512Sgblack@eecs.umich.edu return exitImpl(desc, callnum, tc, false); 2264512Sgblack@eecs.umich.edu} 2274483Sgblack@eecs.umich.edu 2284566Sgblack@eecs.umich.eduSyscallReturn 2294483Sgblack@eecs.umich.eduexitGroupFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2304566Sgblack@eecs.umich.edu{ 2314566Sgblack@eecs.umich.edu return exitImpl(desc, callnum, tc, true); 2324566Sgblack@eecs.umich.edu} 2334566Sgblack@eecs.umich.edu 2344566Sgblack@eecs.umich.eduSyscallReturn 2354483Sgblack@eecs.umich.edugetpagesizeFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2364483Sgblack@eecs.umich.edu{ 2374483Sgblack@eecs.umich.edu return (int)PageBytes; 2384613Sgblack@eecs.umich.edu} 2394613Sgblack@eecs.umich.edu 2404613Sgblack@eecs.umich.edu 2414613Sgblack@eecs.umich.eduSyscallReturn 2424613Sgblack@eecs.umich.edubrkFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2434613Sgblack@eecs.umich.edu{ 2444613Sgblack@eecs.umich.edu // change brk addr to first arg 2454613Sgblack@eecs.umich.edu int index = 0; 2464613Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 2474613Sgblack@eecs.umich.edu Addr new_brk = p->getSyscallArg(tc, index); 2484613Sgblack@eecs.umich.edu 2494613Sgblack@eecs.umich.edu std::shared_ptr<MemState> mem_state = p->memState; 2504613Sgblack@eecs.umich.edu Addr brk_point = mem_state->getBrkPoint(); 2514613Sgblack@eecs.umich.edu 2524613Sgblack@eecs.umich.edu // in Linux at least, brk(0) returns the current break value 2534613Sgblack@eecs.umich.edu // (note that the syscall and the glibc function have different behavior) 2544613Sgblack@eecs.umich.edu if (new_brk == 0) 2554512Sgblack@eecs.umich.edu return brk_point; 2564483Sgblack@eecs.umich.edu 2574483Sgblack@eecs.umich.edu if (new_brk > brk_point) { 2584483Sgblack@eecs.umich.edu // might need to allocate some new pages 2594483Sgblack@eecs.umich.edu for (ChunkGenerator gen(brk_point, 2604483Sgblack@eecs.umich.edu new_brk - brk_point, 2614483Sgblack@eecs.umich.edu PageBytes); !gen.done(); gen.next()) { 2624483Sgblack@eecs.umich.edu if (!p->pTable->translate(gen.addr())) 2634483Sgblack@eecs.umich.edu p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 2644483Sgblack@eecs.umich.edu 2654483Sgblack@eecs.umich.edu // if the address is already there, zero it out 2664512Sgblack@eecs.umich.edu else { 2674483Sgblack@eecs.umich.edu uint8_t zero = 0; 2684483Sgblack@eecs.umich.edu PortProxy &tp = tc->getVirtProxy(); 2694483Sgblack@eecs.umich.edu 2704483Sgblack@eecs.umich.edu // split non-page aligned accesses 2714512Sgblack@eecs.umich.edu Addr next_page = roundUp(gen.addr(), PageBytes); 2724512Sgblack@eecs.umich.edu uint32_t size_needed = next_page - gen.addr(); 2734483Sgblack@eecs.umich.edu tp.memsetBlob(gen.addr(), zero, size_needed); 2744483Sgblack@eecs.umich.edu if (gen.addr() + PageBytes > next_page && 2754483Sgblack@eecs.umich.edu next_page < new_brk && 2764483Sgblack@eecs.umich.edu p->pTable->translate(next_page)) { 2774483Sgblack@eecs.umich.edu size_needed = PageBytes - size_needed; 2784512Sgblack@eecs.umich.edu tp.memsetBlob(next_page, zero, size_needed); 2794512Sgblack@eecs.umich.edu } 2804483Sgblack@eecs.umich.edu } 2814483Sgblack@eecs.umich.edu } 2824483Sgblack@eecs.umich.edu } 2834483Sgblack@eecs.umich.edu 2844483Sgblack@eecs.umich.edu mem_state->setBrkPoint(new_brk); 2854483Sgblack@eecs.umich.edu DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 2864483Sgblack@eecs.umich.edu mem_state->getBrkPoint()); 2874483Sgblack@eecs.umich.edu return mem_state->getBrkPoint(); 2884483Sgblack@eecs.umich.edu} 2894483Sgblack@eecs.umich.edu 2904483Sgblack@eecs.umich.eduSyscallReturn 2914483Sgblack@eecs.umich.edusetTidAddressFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2924483Sgblack@eecs.umich.edu{ 2934483Sgblack@eecs.umich.edu int index = 0; 2944483Sgblack@eecs.umich.edu auto process = tc->getProcessPtr(); 2954483Sgblack@eecs.umich.edu uint64_t tidPtr = process->getSyscallArg(tc, index); 2964483Sgblack@eecs.umich.edu 2974483Sgblack@eecs.umich.edu process->childClearTID = tidPtr; 2984483Sgblack@eecs.umich.edu return process->pid(); 2994483Sgblack@eecs.umich.edu} 3004483Sgblack@eecs.umich.edu 3014483Sgblack@eecs.umich.eduSyscallReturn 3024483Sgblack@eecs.umich.educloseFunc(SyscallDesc *desc, int num, ThreadContext *tc) 3034483Sgblack@eecs.umich.edu{ 3044483Sgblack@eecs.umich.edu int index = 0; 3054483Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 3064483Sgblack@eecs.umich.edu int tgt_fd = p->getSyscallArg(tc, index); 3074483Sgblack@eecs.umich.edu 3084483Sgblack@eecs.umich.edu return p->fds->closeFDEntry(tgt_fd); 3094483Sgblack@eecs.umich.edu} 3104483Sgblack@eecs.umich.edu 3114483Sgblack@eecs.umich.eduSyscallReturn 3124483Sgblack@eecs.umich.edulseekFunc(SyscallDesc *desc, int num, ThreadContext *tc) 3134483Sgblack@eecs.umich.edu{ 3144483Sgblack@eecs.umich.edu int index = 0; 3154483Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 3164483Sgblack@eecs.umich.edu int tgt_fd = p->getSyscallArg(tc, index); 3174483Sgblack@eecs.umich.edu uint64_t offs = p->getSyscallArg(tc, index); 3184483Sgblack@eecs.umich.edu int whence = p->getSyscallArg(tc, index); 3194483Sgblack@eecs.umich.edu 3204483Sgblack@eecs.umich.edu auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 3214483Sgblack@eecs.umich.edu if (!ffdp) 3224483Sgblack@eecs.umich.edu return -EBADF; 3234483Sgblack@eecs.umich.edu int sim_fd = ffdp->getSimFD(); 3244483Sgblack@eecs.umich.edu 3254483Sgblack@eecs.umich.edu off_t result = lseek(sim_fd, offs, whence); 3264483Sgblack@eecs.umich.edu 3274512Sgblack@eecs.umich.edu return (result == (off_t)-1) ? -errno : result; 3284512Sgblack@eecs.umich.edu} 3294483Sgblack@eecs.umich.edu 3304483Sgblack@eecs.umich.edu 3314483Sgblack@eecs.umich.eduSyscallReturn 3324483Sgblack@eecs.umich.edu_llseekFunc(SyscallDesc *desc, int num, ThreadContext *tc) 3334507Sgblack@eecs.umich.edu{ 3344507Sgblack@eecs.umich.edu int index = 0; 3354507Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 3364483Sgblack@eecs.umich.edu int tgt_fd = p->getSyscallArg(tc, index); 3374483Sgblack@eecs.umich.edu uint64_t offset_high = p->getSyscallArg(tc, index); 3384483Sgblack@eecs.umich.edu uint32_t offset_low = p->getSyscallArg(tc, index); 3394483Sgblack@eecs.umich.edu Addr result_ptr = p->getSyscallArg(tc, index); 3404483Sgblack@eecs.umich.edu int whence = p->getSyscallArg(tc, index); 3414483Sgblack@eecs.umich.edu 3424502Sgblack@eecs.umich.edu auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 3434507Sgblack@eecs.umich.edu if (!ffdp) 3444507Sgblack@eecs.umich.edu return -EBADF; 3454507Sgblack@eecs.umich.edu int sim_fd = ffdp->getSimFD(); 3464507Sgblack@eecs.umich.edu 3474508Sgblack@eecs.umich.edu uint64_t offset = (offset_high << 32) | offset_low; 3484507Sgblack@eecs.umich.edu 3494483Sgblack@eecs.umich.edu uint64_t result = lseek(sim_fd, offset, whence); 3504483Sgblack@eecs.umich.edu result = TheISA::htog(result); 3514483Sgblack@eecs.umich.edu 3524483Sgblack@eecs.umich.edu if (result == (off_t)-1) 3534483Sgblack@eecs.umich.edu return -errno; 3544483Sgblack@eecs.umich.edu // Assuming that the size of loff_t is 64 bits on the target platform 3554483Sgblack@eecs.umich.edu BufferArg result_buf(result_ptr, sizeof(result)); 3564483Sgblack@eecs.umich.edu memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 3574483Sgblack@eecs.umich.edu result_buf.copyOut(tc->getVirtProxy()); 3584483Sgblack@eecs.umich.edu return 0; 3594483Sgblack@eecs.umich.edu} 3604502Sgblack@eecs.umich.edu 3614483Sgblack@eecs.umich.edu 3624512Sgblack@eecs.umich.eduSyscallReturn 3634512Sgblack@eecs.umich.edumunmapFunc(SyscallDesc *desc, int num, ThreadContext *tc) 3644512Sgblack@eecs.umich.edu{ 3654512Sgblack@eecs.umich.edu // With mmap more fully implemented, it might be worthwhile to bite 3664512Sgblack@eecs.umich.edu // the bullet and implement munmap. Should allow us to reuse simulated 3674512Sgblack@eecs.umich.edu // memory. 3684512Sgblack@eecs.umich.edu return 0; 3694483Sgblack@eecs.umich.edu} 3704483Sgblack@eecs.umich.edu 3714483Sgblack@eecs.umich.edu 3724483Sgblack@eecs.umich.educonst char *hostname = "m5.eecs.umich.edu"; 3734483Sgblack@eecs.umich.edu 3744483Sgblack@eecs.umich.eduSyscallReturn 3754483Sgblack@eecs.umich.edugethostnameFunc(SyscallDesc *desc, int num, ThreadContext *tc) 3764483Sgblack@eecs.umich.edu{ 3774483Sgblack@eecs.umich.edu int index = 0; 3784483Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 3794483Sgblack@eecs.umich.edu Addr buf_ptr = p->getSyscallArg(tc, index); 3804483Sgblack@eecs.umich.edu int name_len = p->getSyscallArg(tc, index); 3814483Sgblack@eecs.umich.edu BufferArg name(buf_ptr, name_len); 3824483Sgblack@eecs.umich.edu 3834483Sgblack@eecs.umich.edu strncpy((char *)name.bufferPtr(), hostname, name_len); 3844483Sgblack@eecs.umich.edu 3854483Sgblack@eecs.umich.edu name.copyOut(tc->getVirtProxy()); 3864483Sgblack@eecs.umich.edu 3874483Sgblack@eecs.umich.edu return 0; 3884483Sgblack@eecs.umich.edu} 3894483Sgblack@eecs.umich.edu 3904483Sgblack@eecs.umich.eduSyscallReturn 3914483Sgblack@eecs.umich.edugetcwdFunc(SyscallDesc *desc, int num, ThreadContext *tc) 3924512Sgblack@eecs.umich.edu{ 3934483Sgblack@eecs.umich.edu int result = 0; 3944483Sgblack@eecs.umich.edu int index = 0; 3954483Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 3964483Sgblack@eecs.umich.edu Addr buf_ptr = p->getSyscallArg(tc, index); 3974483Sgblack@eecs.umich.edu unsigned long size = p->getSyscallArg(tc, index); 3984483Sgblack@eecs.umich.edu BufferArg buf(buf_ptr, size); 3994483Sgblack@eecs.umich.edu 4004483Sgblack@eecs.umich.edu // Is current working directory defined? 4014483Sgblack@eecs.umich.edu string cwd = p->tgtCwd; 4024483Sgblack@eecs.umich.edu if (!cwd.empty()) { 4034512Sgblack@eecs.umich.edu if (cwd.length() >= size) { 4044483Sgblack@eecs.umich.edu // Buffer too small 4054483Sgblack@eecs.umich.edu return -ERANGE; 4064483Sgblack@eecs.umich.edu } 4074483Sgblack@eecs.umich.edu strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 4084483Sgblack@eecs.umich.edu result = cwd.length(); 4094483Sgblack@eecs.umich.edu } else { 4104483Sgblack@eecs.umich.edu if (getcwd((char *)buf.bufferPtr(), size)) { 4114483Sgblack@eecs.umich.edu result = strlen((char *)buf.bufferPtr()); 4124483Sgblack@eecs.umich.edu } else { 4134483Sgblack@eecs.umich.edu result = -1; 4144483Sgblack@eecs.umich.edu } 4154483Sgblack@eecs.umich.edu } 4164483Sgblack@eecs.umich.edu 4174483Sgblack@eecs.umich.edu buf.copyOut(tc->getVirtProxy()); 4184483Sgblack@eecs.umich.edu 4194483Sgblack@eecs.umich.edu return (result == -1) ? -errno : result; 4204483Sgblack@eecs.umich.edu} 4214483Sgblack@eecs.umich.edu 4224483Sgblack@eecs.umich.eduSyscallReturn 4234483Sgblack@eecs.umich.edureadlinkFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 4244483Sgblack@eecs.umich.edu{ 4254483Sgblack@eecs.umich.edu return readlinkFunc(desc, callnum, tc, 0); 4264483Sgblack@eecs.umich.edu} 4274483Sgblack@eecs.umich.edu 4284483Sgblack@eecs.umich.eduSyscallReturn 4294483Sgblack@eecs.umich.edureadlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc, int index) 4304483Sgblack@eecs.umich.edu{ 4314483Sgblack@eecs.umich.edu string path; 4324512Sgblack@eecs.umich.edu auto p = tc->getProcessPtr(); 4334483Sgblack@eecs.umich.edu 4344483Sgblack@eecs.umich.edu if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 4354483Sgblack@eecs.umich.edu return -EFAULT; 4364483Sgblack@eecs.umich.edu 4374483Sgblack@eecs.umich.edu // Adjust path for cwd and redirection 4384483Sgblack@eecs.umich.edu path = p->checkPathRedirect(path); 4394483Sgblack@eecs.umich.edu 4404483Sgblack@eecs.umich.edu Addr buf_ptr = p->getSyscallArg(tc, index); 4414483Sgblack@eecs.umich.edu size_t bufsiz = p->getSyscallArg(tc, index); 4424483Sgblack@eecs.umich.edu 4434483Sgblack@eecs.umich.edu BufferArg buf(buf_ptr, bufsiz); 4444483Sgblack@eecs.umich.edu 4454483Sgblack@eecs.umich.edu int result = -1; 4464483Sgblack@eecs.umich.edu if (path != "/proc/self/exe") { 4474483Sgblack@eecs.umich.edu result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 4484483Sgblack@eecs.umich.edu } else { 4494483Sgblack@eecs.umich.edu // Emulate readlink() called on '/proc/self/exe' should return the 4504483Sgblack@eecs.umich.edu // absolute path of the binary running in the simulated system (the 4514483Sgblack@eecs.umich.edu // Process' executable). It is possible that using this path in 4524483Sgblack@eecs.umich.edu // the simulated system will result in unexpected behavior if: 4534483Sgblack@eecs.umich.edu // 1) One binary runs another (e.g., -c time -o "my_binary"), and 4544483Sgblack@eecs.umich.edu // called binary calls readlink(). 4554483Sgblack@eecs.umich.edu // 2) The host's full path to the running benchmark changes from one 4564512Sgblack@eecs.umich.edu // simulation to another. This can result in different simulated 4574503Sgblack@eecs.umich.edu // performance since the simulated system will process the binary 4584483Sgblack@eecs.umich.edu // path differently, even if the binary itself does not change. 4594483Sgblack@eecs.umich.edu 4604483Sgblack@eecs.umich.edu // Get the absolute canonical path to the running application 4614483Sgblack@eecs.umich.edu char real_path[PATH_MAX]; 4624483Sgblack@eecs.umich.edu char *check_real_path = realpath(p->progName(), real_path); 4634503Sgblack@eecs.umich.edu if (!check_real_path) { 4644503Sgblack@eecs.umich.edu fatal("readlink('/proc/self/exe') unable to resolve path to " 4654503Sgblack@eecs.umich.edu "executable: %s", p->progName()); 4664503Sgblack@eecs.umich.edu } 4674503Sgblack@eecs.umich.edu strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 4684503Sgblack@eecs.umich.edu size_t real_path_len = strlen(real_path); 4694503Sgblack@eecs.umich.edu if (real_path_len > bufsiz) { 4704483Sgblack@eecs.umich.edu // readlink will truncate the contents of the 4714483Sgblack@eecs.umich.edu // path to ensure it is no more than bufsiz 4724483Sgblack@eecs.umich.edu result = bufsiz; 4734483Sgblack@eecs.umich.edu } else { 4744483Sgblack@eecs.umich.edu result = real_path_len; 4754483Sgblack@eecs.umich.edu } 4764483Sgblack@eecs.umich.edu 4774483Sgblack@eecs.umich.edu // Issue a warning about potential unexpected results 4784483Sgblack@eecs.umich.edu warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 4794483Sgblack@eecs.umich.edu "results in various settings.\n Returning '%s'\n", 4804507Sgblack@eecs.umich.edu (char*)buf.bufferPtr()); 4814507Sgblack@eecs.umich.edu } 4824483Sgblack@eecs.umich.edu 4834483Sgblack@eecs.umich.edu buf.copyOut(tc->getVirtProxy()); 4844483Sgblack@eecs.umich.edu 4854502Sgblack@eecs.umich.edu return (result == -1) ? -errno : result; 4864483Sgblack@eecs.umich.edu} 4874483Sgblack@eecs.umich.edu 4884507Sgblack@eecs.umich.eduSyscallReturn 4894613Sgblack@eecs.umich.eduunlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc) 4904613Sgblack@eecs.umich.edu{ 4914483Sgblack@eecs.umich.edu return unlinkHelper(desc, num, tc, 0); 4924483Sgblack@eecs.umich.edu} 4934483Sgblack@eecs.umich.edu 4944483Sgblack@eecs.umich.eduSyscallReturn 4954502Sgblack@eecs.umich.eduunlinkHelper(SyscallDesc *desc, int num, ThreadContext *tc, int index) 4964483Sgblack@eecs.umich.edu{ 497 string path; 498 auto p = tc->getProcessPtr(); 499 500 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 501 return -EFAULT; 502 503 path = p->checkPathRedirect(path); 504 505 int result = unlink(path.c_str()); 506 return (result == -1) ? -errno : result; 507} 508 509SyscallReturn 510linkFunc(SyscallDesc *desc, int num, ThreadContext *tc) 511{ 512 string path; 513 string new_path; 514 auto p = tc->getProcessPtr(); 515 516 int index = 0; 517 auto &virt_mem = tc->getVirtProxy(); 518 if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index))) 519 return -EFAULT; 520 if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index))) 521 return -EFAULT; 522 523 path = p->absolutePath(path, true); 524 new_path = p->absolutePath(new_path, true); 525 526 int result = link(path.c_str(), new_path.c_str()); 527 return (result == -1) ? -errno : result; 528} 529 530SyscallReturn 531symlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc) 532{ 533 string path; 534 string new_path; 535 auto p = tc->getProcessPtr(); 536 537 int index = 0; 538 auto &virt_mem = tc->getVirtProxy(); 539 if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index))) 540 return -EFAULT; 541 if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index))) 542 return -EFAULT; 543 544 path = p->absolutePath(path, true); 545 new_path = p->absolutePath(new_path, true); 546 547 int result = symlink(path.c_str(), new_path.c_str()); 548 return (result == -1) ? -errno : result; 549} 550 551SyscallReturn 552mkdirFunc(SyscallDesc *desc, int num, ThreadContext *tc) 553{ 554 auto p = tc->getProcessPtr(); 555 int index = 0; 556 std::string path; 557 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 558 return -EFAULT; 559 560 path = p->checkPathRedirect(path); 561 mode_t mode = p->getSyscallArg(tc, index); 562 563 auto result = mkdir(path.c_str(), mode); 564 return (result == -1) ? -errno : result; 565} 566 567SyscallReturn 568renameFunc(SyscallDesc *desc, int num, ThreadContext *tc) 569{ 570 string old_name; 571 auto p = tc->getProcessPtr(); 572 573 int index = 0; 574 if (!tc->getVirtProxy().tryReadString( 575 old_name, p->getSyscallArg(tc, index))) { 576 return -EFAULT; 577 } 578 579 string new_name; 580 581 if (!tc->getVirtProxy().tryReadString( 582 new_name, p->getSyscallArg(tc, index))) { 583 return -EFAULT; 584 } 585 586 // Adjust path for cwd and redirection 587 old_name = p->checkPathRedirect(old_name); 588 new_name = p->checkPathRedirect(new_name); 589 590 int64_t result = rename(old_name.c_str(), new_name.c_str()); 591 return (result == -1) ? -errno : result; 592} 593 594SyscallReturn 595truncateFunc(SyscallDesc *desc, int num, ThreadContext *tc) 596{ 597 string path; 598 auto p = tc->getProcessPtr(); 599 600 int index = 0; 601 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 602 return -EFAULT; 603 604 off_t length = p->getSyscallArg(tc, index); 605 606 // Adjust path for cwd and redirection 607 path = p->checkPathRedirect(path); 608 609 int result = truncate(path.c_str(), length); 610 return (result == -1) ? -errno : result; 611} 612 613SyscallReturn 614ftruncateFunc(SyscallDesc *desc, int num, ThreadContext *tc) 615{ 616 int index = 0; 617 auto p = tc->getProcessPtr(); 618 int tgt_fd = p->getSyscallArg(tc, index); 619 off_t length = p->getSyscallArg(tc, index); 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 int result = ftruncate(sim_fd, length); 627 return (result == -1) ? -errno : result; 628} 629 630SyscallReturn 631truncate64Func(SyscallDesc *desc, int num, ThreadContext *tc) 632{ 633 int index = 0; 634 auto process = tc->getProcessPtr(); 635 string path; 636 637 if (!tc->getVirtProxy().tryReadString( 638 path, process->getSyscallArg(tc, index))) { 639 return -EFAULT; 640 } 641 642 int64_t length = process->getSyscallArg(tc, index, 64); 643 644 // Adjust path for cwd and redirection 645 path = process->checkPathRedirect(path); 646 647#if NO_STAT64 648 int result = truncate(path.c_str(), length); 649#else 650 int result = truncate64(path.c_str(), length); 651#endif 652 return (result == -1) ? -errno : result; 653} 654 655SyscallReturn 656ftruncate64Func(SyscallDesc *desc, int num, ThreadContext *tc) 657{ 658 int index = 0; 659 auto p = tc->getProcessPtr(); 660 int tgt_fd = p->getSyscallArg(tc, index); 661 int64_t length = p->getSyscallArg(tc, index, 64); 662 663 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 664 if (!ffdp) 665 return -EBADF; 666 int sim_fd = ffdp->getSimFD(); 667 668#if NO_STAT64 669 int result = ftruncate(sim_fd, length); 670#else 671 int result = ftruncate64(sim_fd, length); 672#endif 673 return (result == -1) ? -errno : result; 674} 675 676SyscallReturn 677umaskFunc(SyscallDesc *desc, int num, ThreadContext *tc) 678{ 679 // Letting the simulated program change the simulator's umask seems like 680 // a bad idea. Compromise by just returning the current umask but not 681 // changing anything. 682 mode_t oldMask = umask(0); 683 umask(oldMask); 684 return (int)oldMask; 685} 686 687SyscallReturn 688chownFunc(SyscallDesc *desc, int num, ThreadContext *tc) 689{ 690 string path; 691 auto p = tc->getProcessPtr(); 692 693 int index = 0; 694 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 695 return -EFAULT; 696 697 /* XXX endianess */ 698 uint32_t owner = p->getSyscallArg(tc, index); 699 uid_t hostOwner = owner; 700 uint32_t group = p->getSyscallArg(tc, index); 701 gid_t hostGroup = group; 702 703 // Adjust path for cwd and redirection 704 path = p->checkPathRedirect(path); 705 706 int result = chown(path.c_str(), hostOwner, hostGroup); 707 return (result == -1) ? -errno : result; 708} 709 710SyscallReturn 711fchownFunc(SyscallDesc *desc, int num, ThreadContext *tc) 712{ 713 int index = 0; 714 auto p = tc->getProcessPtr(); 715 int tgt_fd = p->getSyscallArg(tc, index); 716 717 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 718 if (!ffdp) 719 return -EBADF; 720 int sim_fd = ffdp->getSimFD(); 721 722 /* XXX endianess */ 723 uint32_t owner = p->getSyscallArg(tc, index); 724 uid_t hostOwner = owner; 725 uint32_t group = p->getSyscallArg(tc, index); 726 gid_t hostGroup = group; 727 728 int result = fchown(sim_fd, hostOwner, hostGroup); 729 return (result == -1) ? -errno : result; 730} 731 732/** 733 * FIXME: The file description is not shared among file descriptors created 734 * with dup. Really, it's difficult to maintain fields like file offset or 735 * flags since an update to such a field won't be reflected in the metadata 736 * for the fd entries that we maintain for checkpoint restoration. 737 */ 738SyscallReturn 739dupFunc(SyscallDesc *desc, int num, ThreadContext *tc) 740{ 741 int index = 0; 742 auto p = tc->getProcessPtr(); 743 int tgt_fd = p->getSyscallArg(tc, index); 744 745 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 746 if (!old_hbfdp) 747 return -EBADF; 748 int sim_fd = old_hbfdp->getSimFD(); 749 750 int result = dup(sim_fd); 751 if (result == -1) 752 return -errno; 753 754 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone()); 755 new_hbfdp->setSimFD(result); 756 new_hbfdp->setCOE(false); 757 return p->fds->allocFD(new_hbfdp); 758} 759 760SyscallReturn 761dup2Func(SyscallDesc *desc, int num, ThreadContext *tc) 762{ 763 int index = 0; 764 auto p = tc->getProcessPtr(); 765 int old_tgt_fd = p->getSyscallArg(tc, index); 766 auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]); 767 if (!old_hbp) 768 return -EBADF; 769 int old_sim_fd = old_hbp->getSimFD(); 770 771 /** 772 * We need a valid host file descriptor number to be able to pass into 773 * the second parameter for dup2 (newfd), but we don't know what the 774 * viable numbers are; we execute the open call to retrieve one. 775 */ 776 int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY)); 777 if (res_fd == -1) 778 return -errno; 779 780 int new_tgt_fd = p->getSyscallArg(tc, index); 781 auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]); 782 if (new_hbp) 783 p->fds->closeFDEntry(new_tgt_fd); 784 new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone()); 785 new_hbp->setSimFD(res_fd); 786 new_hbp->setCOE(false); 787 788 return p->fds->allocFD(new_hbp); 789} 790 791SyscallReturn 792fcntlFunc(SyscallDesc *desc, int num, ThreadContext *tc) 793{ 794 int arg; 795 int index = 0; 796 auto p = tc->getProcessPtr(); 797 int tgt_fd = p->getSyscallArg(tc, index); 798 int cmd = p->getSyscallArg(tc, index); 799 800 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 801 if (!hbfdp) 802 return -EBADF; 803 int sim_fd = hbfdp->getSimFD(); 804 805 int coe = hbfdp->getCOE(); 806 807 switch (cmd) { 808 case F_GETFD: 809 return coe & FD_CLOEXEC; 810 811 case F_SETFD: { 812 arg = p->getSyscallArg(tc, index); 813 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 814 return 0; 815 } 816 817 // Rely on the host to maintain the file status flags for this file 818 // description rather than maintain it ourselves. Admittedly, this 819 // is suboptimal (and possibly error prone), but it is difficult to 820 // maintain the flags by tracking them across the different descriptors 821 // (that refer to this file description) caused by clone, dup, and 822 // subsequent fcntls. 823 case F_GETFL: 824 case F_SETFL: { 825 arg = p->getSyscallArg(tc, index); 826 int rv = fcntl(sim_fd, cmd, arg); 827 return (rv == -1) ? -errno : rv; 828 } 829 830 default: 831 warn("fcntl: unsupported command %d\n", cmd); 832 return 0; 833 } 834} 835 836SyscallReturn 837fcntl64Func(SyscallDesc *desc, int num, ThreadContext *tc) 838{ 839 int index = 0; 840 auto p = tc->getProcessPtr(); 841 int tgt_fd = p->getSyscallArg(tc, index); 842 843 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 844 if (!hbfdp) 845 return -EBADF; 846 int sim_fd = hbfdp->getSimFD(); 847 848 int cmd = p->getSyscallArg(tc, index); 849 switch (cmd) { 850 case 33: //F_GETLK64 851 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 852 return -EMFILE; 853 854 case 34: // F_SETLK64 855 case 35: // F_SETLKW64 856 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 857 tgt_fd); 858 return -EMFILE; 859 860 default: 861 // not sure if this is totally valid, but we'll pass it through 862 // to the underlying OS 863 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 864 return fcntl(sim_fd, cmd); 865 } 866} 867 868SyscallReturn 869pipeImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool pseudoPipe) 870{ 871 Addr tgt_addr = 0; 872 auto p = tc->getProcessPtr(); 873 if (!pseudoPipe) { 874 int index = 0; 875 tgt_addr = p->getSyscallArg(tc, index); 876 } 877 878 int sim_fds[2], tgt_fds[2]; 879 880 int pipe_retval = pipe(sim_fds); 881 if (pipe_retval == -1) 882 return -errno; 883 884 auto rend = PipeFDEntry::EndType::read; 885 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 886 tgt_fds[0] = p->fds->allocFD(rpfd); 887 888 auto wend = PipeFDEntry::EndType::write; 889 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 890 tgt_fds[1] = p->fds->allocFD(wpfd); 891 892 /** 893 * Now patch the read object to record the target file descriptor chosen 894 * as the write end of the pipe. 895 */ 896 rpfd->setPipeReadSource(tgt_fds[1]); 897 898 /** 899 * Alpha Linux convention for pipe() is that fd[0] is returned as 900 * the return value of the function, and fd[1] is returned in r20. 901 */ 902 if (pseudoPipe) { 903 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 904 return tgt_fds[0]; 905 } 906 907 /** 908 * Copy the target file descriptors into buffer space and then copy 909 * the buffer space back into the target address space. 910 */ 911 BufferArg tgt_handle(tgt_addr, sizeof(int[2])); 912 int *buf_ptr = (int*)tgt_handle.bufferPtr(); 913 buf_ptr[0] = tgt_fds[0]; 914 buf_ptr[1] = tgt_fds[1]; 915 tgt_handle.copyOut(tc->getVirtProxy()); 916 return 0; 917} 918 919SyscallReturn 920pipePseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 921{ 922 return pipeImpl(desc, callnum, tc, true); 923} 924 925SyscallReturn 926pipeFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 927{ 928 return pipeImpl(desc, callnum, tc, false); 929} 930 931SyscallReturn 932setpgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 933{ 934 int index = 0; 935 auto process = tc->getProcessPtr(); 936 int pid = process->getSyscallArg(tc, index); 937 int pgid = process->getSyscallArg(tc, index); 938 939 if (pgid < 0) 940 return -EINVAL; 941 942 if (pid == 0) { 943 process->setpgid(process->pid()); 944 return 0; 945 } 946 947 Process *matched_ph = nullptr; 948 System *sysh = tc->getSystemPtr(); 949 950 // Retrieves process pointer from active/suspended thread contexts. 951 for (int i = 0; i < sysh->numContexts(); i++) { 952 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 953 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 954 Process *walk_ph = (Process*)temp_h; 955 956 if (walk_ph && walk_ph->pid() == process->pid()) 957 matched_ph = walk_ph; 958 } 959 } 960 961 assert(matched_ph); 962 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 963 964 return 0; 965} 966 967SyscallReturn 968getpidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 969{ 970 // Make up a PID. There's no interprocess communication in 971 // fake_syscall mode, so there's no way for a process to know it's 972 // not getting a unique value. 973 974 auto process = tc->getProcessPtr(); 975 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 976 return process->pid(); 977} 978 979 980SyscallReturn 981getuidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 982{ 983 // Make up a UID and EUID... it shouldn't matter, and we want the 984 // simulation to be deterministic. 985 986 // EUID goes in r20. 987 auto process = tc->getProcessPtr(); 988 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 989 return process->uid(); // UID 990} 991 992 993SyscallReturn 994getgidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 995{ 996 // Get current group ID. EGID goes in r20. 997 auto process = tc->getProcessPtr(); 998 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 999 return process->gid(); 1000} 1001 1002 1003SyscallReturn 1004setuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1005{ 1006 // can't fathom why a benchmark would call this. 1007 int index = 0; 1008 auto process = tc->getProcessPtr(); 1009 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 1010 return 0; 1011} 1012 1013SyscallReturn 1014getpidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1015{ 1016 auto process = tc->getProcessPtr(); 1017 return process->tgid(); 1018} 1019 1020SyscallReturn 1021gettidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1022{ 1023 auto process = tc->getProcessPtr(); 1024 return process->pid(); 1025} 1026 1027SyscallReturn 1028getppidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1029{ 1030 auto process = tc->getProcessPtr(); 1031 return process->ppid(); 1032} 1033 1034SyscallReturn 1035getuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1036{ 1037 auto process = tc->getProcessPtr(); 1038 return process->uid(); // UID 1039} 1040 1041SyscallReturn 1042geteuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1043{ 1044 auto process = tc->getProcessPtr(); 1045 return process->euid(); // UID 1046} 1047 1048SyscallReturn 1049getgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1050{ 1051 auto process = tc->getProcessPtr(); 1052 return process->gid(); 1053} 1054 1055SyscallReturn 1056getegidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1057{ 1058 auto process = tc->getProcessPtr(); 1059 return process->egid(); 1060} 1061 1062SyscallReturn 1063fallocateFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1064{ 1065#if defined(__linux__) 1066 int index = 0; 1067 auto p = tc->getProcessPtr(); 1068 int tgt_fd = p->getSyscallArg(tc, index); 1069 int mode = p->getSyscallArg(tc, index); 1070 off_t offset = p->getSyscallArg(tc, index); 1071 off_t len = p->getSyscallArg(tc, index); 1072 1073 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1074 if (!ffdp) 1075 return -EBADF; 1076 int sim_fd = ffdp->getSimFD(); 1077 1078 int result = fallocate(sim_fd, mode, offset, len); 1079 if (result < 0) 1080 return -errno; 1081 return 0; 1082#else 1083 warnUnsupportedOS("fallocate"); 1084 return -1; 1085#endif 1086} 1087 1088SyscallReturn 1089accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int index) 1090{ 1091 string path; 1092 auto p = tc->getProcessPtr(); 1093 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1094 return -EFAULT; 1095 1096 // Adjust path for cwd and redirection 1097 path = p->checkPathRedirect(path); 1098 1099 mode_t mode = p->getSyscallArg(tc, index); 1100 1101 int result = access(path.c_str(), mode); 1102 return (result == -1) ? -errno : result; 1103} 1104 1105SyscallReturn 1106accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1107{ 1108 return accessFunc(desc, callnum, tc, 0); 1109} 1110 1111SyscallReturn 1112mknodFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1113{ 1114 auto p = tc->getProcessPtr(); 1115 int index = 0; 1116 std::string path; 1117 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1118 return -EFAULT; 1119 1120 path = p->checkPathRedirect(path); 1121 mode_t mode = p->getSyscallArg(tc, index); 1122 dev_t dev = p->getSyscallArg(tc, index); 1123 1124 auto result = mknod(path.c_str(), mode, dev); 1125 return (result == -1) ? -errno : result; 1126} 1127 1128SyscallReturn 1129chdirFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1130{ 1131 auto p = tc->getProcessPtr(); 1132 int index = 0; 1133 std::string path; 1134 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1135 return -EFAULT; 1136 1137 std::string tgt_cwd; 1138 if (startswith(path, "/")) { 1139 tgt_cwd = path; 1140 } else { 1141 char buf[PATH_MAX]; 1142 tgt_cwd = realpath((p->tgtCwd + "/" + path).c_str(), buf); 1143 } 1144 std::string host_cwd = p->checkPathRedirect(tgt_cwd); 1145 1146 int result = chdir(host_cwd.c_str()); 1147 1148 if (result == -1) 1149 return -errno; 1150 1151 p->hostCwd = host_cwd; 1152 p->tgtCwd = tgt_cwd; 1153 return result; 1154} 1155 1156SyscallReturn 1157rmdirFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1158{ 1159 auto p = tc->getProcessPtr(); 1160 int index = 0; 1161 std::string path; 1162 if (!tc->getVirtProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1163 return -EFAULT; 1164 1165 path = p->checkPathRedirect(path); 1166 1167 auto result = rmdir(path.c_str()); 1168 return (result == -1) ? -errno : result; 1169} 1170 1171#if defined(SYS_getdents) || defined(SYS_getdents64) 1172template<typename DE, int SYS_NUM> 1173static SyscallReturn 1174getdentsImpl(SyscallDesc *desc, int callnum, ThreadContext *tc) 1175{ 1176 int index = 0; 1177 auto p = tc->getProcessPtr(); 1178 int tgt_fd = p->getSyscallArg(tc, index); 1179 Addr buf_ptr = p->getSyscallArg(tc, index); 1180 unsigned count = p->getSyscallArg(tc, index); 1181 1182 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1183 if (!hbfdp) 1184 return -EBADF; 1185 int sim_fd = hbfdp->getSimFD(); 1186 1187 BufferArg buf_arg(buf_ptr, count); 1188 auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count); 1189 1190 if (status == -1) 1191 return -errno; 1192 1193 unsigned traversed = 0; 1194 while (traversed < status) { 1195 DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed); 1196 1197 auto host_reclen = buffer->d_reclen; 1198 1199 /** 1200 * Convert the byte ordering from the host to the target before 1201 * passing the data back into the target's address space to preserve 1202 * endianness. 1203 */ 1204 buffer->d_ino = htog(buffer->d_ino); 1205 buffer->d_off = htog(buffer->d_off); 1206 buffer->d_reclen = htog(buffer->d_reclen); 1207 1208 traversed += host_reclen; 1209 } 1210 1211 buf_arg.copyOut(tc->getVirtProxy()); 1212 return status; 1213} 1214#endif 1215 1216#if defined(SYS_getdents) 1217SyscallReturn 1218getdentsFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1219{ 1220 typedef struct linux_dirent { 1221 unsigned long d_ino; 1222 unsigned long d_off; 1223 unsigned short d_reclen; 1224 char dname[]; 1225 } LinDent; 1226 1227 return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, tc); 1228} 1229#endif 1230 1231#if defined(SYS_getdents64) 1232SyscallReturn 1233getdents64Func(SyscallDesc *desc, int callnum, ThreadContext *tc) 1234{ 1235 typedef struct linux_dirent64 { 1236 ino64_t d_ino; 1237 off64_t d_off; 1238 unsigned short d_reclen; 1239 char dname[]; 1240 } LinDent64; 1241 1242 return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, tc); 1243} 1244#endif 1245 1246SyscallReturn 1247shutdownFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1248{ 1249 int index = 0; 1250 auto p = tc->getProcessPtr(); 1251 int tgt_fd = p->getSyscallArg(tc, index); 1252 int how = p->getSyscallArg(tc, index); 1253 1254 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1255 if (!sfdp) 1256 return -EBADF; 1257 int sim_fd = sfdp->getSimFD(); 1258 1259 int retval = shutdown(sim_fd, how); 1260 1261 return (retval == -1) ? -errno : retval; 1262} 1263 1264SyscallReturn 1265bindFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1266{ 1267 int index = 0; 1268 auto p = tc->getProcessPtr(); 1269 int tgt_fd = p->getSyscallArg(tc, index); 1270 Addr buf_ptr = p->getSyscallArg(tc, index); 1271 int addrlen = p->getSyscallArg(tc, index); 1272 1273 BufferArg bufSock(buf_ptr, addrlen); 1274 bufSock.copyIn(tc->getVirtProxy()); 1275 1276 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1277 if (!sfdp) 1278 return -EBADF; 1279 int sim_fd = sfdp->getSimFD(); 1280 1281 int status = ::bind(sim_fd, 1282 (struct sockaddr *)bufSock.bufferPtr(), 1283 addrlen); 1284 1285 return (status == -1) ? -errno : status; 1286} 1287 1288SyscallReturn 1289listenFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1290{ 1291 int index = 0; 1292 auto p = tc->getProcessPtr(); 1293 int tgt_fd = p->getSyscallArg(tc, index); 1294 int backlog = p->getSyscallArg(tc, index); 1295 1296 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1297 if (!sfdp) 1298 return -EBADF; 1299 int sim_fd = sfdp->getSimFD(); 1300 1301 int status = listen(sim_fd, backlog); 1302 1303 return (status == -1) ? -errno : status; 1304} 1305 1306SyscallReturn 1307connectFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1308{ 1309 int index = 0; 1310 auto p = tc->getProcessPtr(); 1311 int tgt_fd = p->getSyscallArg(tc, index); 1312 Addr buf_ptr = p->getSyscallArg(tc, index); 1313 int addrlen = p->getSyscallArg(tc, index); 1314 1315 BufferArg addr(buf_ptr, addrlen); 1316 addr.copyIn(tc->getVirtProxy()); 1317 1318 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1319 if (!sfdp) 1320 return -EBADF; 1321 int sim_fd = sfdp->getSimFD(); 1322 1323 int status = connect(sim_fd, 1324 (struct sockaddr *)addr.bufferPtr(), 1325 (socklen_t)addrlen); 1326 1327 return (status == -1) ? -errno : status; 1328} 1329 1330SyscallReturn 1331recvfromFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1332{ 1333 int index = 0; 1334 auto p = tc->getProcessPtr(); 1335 int tgt_fd = p->getSyscallArg(tc, index); 1336 Addr bufrPtr = p->getSyscallArg(tc, index); 1337 size_t bufrLen = p->getSyscallArg(tc, index); 1338 int flags = p->getSyscallArg(tc, index); 1339 Addr addrPtr = p->getSyscallArg(tc, index); 1340 Addr addrlenPtr = p->getSyscallArg(tc, index); 1341 1342 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1343 if (!sfdp) 1344 return -EBADF; 1345 int sim_fd = sfdp->getSimFD(); 1346 1347 // Reserve buffer space. 1348 BufferArg bufrBuf(bufrPtr, bufrLen); 1349 1350 // Get address length. 1351 socklen_t addrLen = 0; 1352 if (addrlenPtr != 0) { 1353 // Read address length parameter. 1354 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1355 addrlenBuf.copyIn(tc->getVirtProxy()); 1356 addrLen = *((socklen_t *)addrlenBuf.bufferPtr()); 1357 } 1358 1359 struct sockaddr sa, *sap = NULL; 1360 if (addrLen != 0) { 1361 BufferArg addrBuf(addrPtr, addrLen); 1362 addrBuf.copyIn(tc->getVirtProxy()); 1363 memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(), 1364 sizeof(struct sockaddr)); 1365 sap = &sa; 1366 } 1367 1368 ssize_t recvd_size = recvfrom(sim_fd, 1369 (void *)bufrBuf.bufferPtr(), 1370 bufrLen, flags, sap, (socklen_t *)&addrLen); 1371 1372 if (recvd_size == -1) 1373 return -errno; 1374 1375 // Pass the received data out. 1376 bufrBuf.copyOut(tc->getVirtProxy()); 1377 1378 // Copy address to addrPtr and pass it on. 1379 if (sap != NULL) { 1380 BufferArg addrBuf(addrPtr, addrLen); 1381 memcpy(addrBuf.bufferPtr(), sap, sizeof(sa)); 1382 addrBuf.copyOut(tc->getVirtProxy()); 1383 } 1384 1385 // Copy len to addrlenPtr and pass it on. 1386 if (addrLen != 0) { 1387 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1388 *(socklen_t *)addrlenBuf.bufferPtr() = addrLen; 1389 addrlenBuf.copyOut(tc->getVirtProxy()); 1390 } 1391 1392 return recvd_size; 1393} 1394 1395SyscallReturn 1396sendtoFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1397{ 1398 int index = 0; 1399 auto p = tc->getProcessPtr(); 1400 int tgt_fd = p->getSyscallArg(tc, index); 1401 Addr bufrPtr = p->getSyscallArg(tc, index); 1402 size_t bufrLen = p->getSyscallArg(tc, index); 1403 int flags = p->getSyscallArg(tc, index); 1404 Addr addrPtr = p->getSyscallArg(tc, index); 1405 socklen_t addrLen = p->getSyscallArg(tc, index); 1406 1407 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1408 if (!sfdp) 1409 return -EBADF; 1410 int sim_fd = sfdp->getSimFD(); 1411 1412 // Reserve buffer space. 1413 BufferArg bufrBuf(bufrPtr, bufrLen); 1414 bufrBuf.copyIn(tc->getVirtProxy()); 1415 1416 struct sockaddr sa, *sap = nullptr; 1417 memset(&sa, 0, sizeof(sockaddr)); 1418 if (addrLen != 0) { 1419 BufferArg addrBuf(addrPtr, addrLen); 1420 addrBuf.copyIn(tc->getVirtProxy()); 1421 memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen); 1422 sap = &sa; 1423 } 1424 1425 ssize_t sent_size = sendto(sim_fd, 1426 (void *)bufrBuf.bufferPtr(), 1427 bufrLen, flags, sap, (socklen_t)addrLen); 1428 1429 return (sent_size == -1) ? -errno : sent_size; 1430} 1431 1432SyscallReturn 1433recvmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1434{ 1435 int index = 0; 1436 auto p = tc->getProcessPtr(); 1437 int tgt_fd = p->getSyscallArg(tc, index); 1438 Addr msgPtr = p->getSyscallArg(tc, index); 1439 int flags = p->getSyscallArg(tc, index); 1440 1441 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1442 if (!sfdp) 1443 return -EBADF; 1444 int sim_fd = sfdp->getSimFD(); 1445 1446 /** 1447 * struct msghdr { 1448 * void *msg_name; // optional address 1449 * socklen_t msg_namelen; // size of address 1450 * struct iovec *msg_iov; // iovec array 1451 * size_t msg_iovlen; // number entries in msg_iov 1452 * i // entries correspond to buffer 1453 * void *msg_control; // ancillary data 1454 * size_t msg_controllen; // ancillary data buffer len 1455 * int msg_flags; // flags on received message 1456 * }; 1457 * 1458 * struct iovec { 1459 * void *iov_base; // starting address 1460 * size_t iov_len; // number of bytes to transfer 1461 * }; 1462 */ 1463 1464 /** 1465 * The plan with this system call is to replace all of the pointers in the 1466 * structure and the substructure with BufferArg class pointers. We will 1467 * copy every field from the structures into our BufferArg classes. 1468 */ 1469 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1470 msgBuf.copyIn(tc->getVirtProxy()); 1471 struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr(); 1472 1473 /** 1474 * We will use these address place holders to retain the pointers which 1475 * we are going to replace with our own buffers in our simulator address 1476 * space. 1477 */ 1478 Addr msg_name_phold = 0; 1479 Addr msg_iov_phold = 0; 1480 Addr iovec_base_phold[msgHdr->msg_iovlen]; 1481 Addr msg_control_phold = 0; 1482 1483 /** 1484 * Record msg_name pointer then replace with buffer pointer. 1485 */ 1486 BufferArg *nameBuf = NULL; 1487 if (msgHdr->msg_name) { 1488 /*1*/msg_name_phold = (Addr)msgHdr->msg_name; 1489 /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen); 1490 /*3*/nameBuf->copyIn(tc->getVirtProxy()); 1491 /*4*/msgHdr->msg_name = nameBuf->bufferPtr(); 1492 } 1493 1494 /** 1495 * Record msg_iov pointer then replace with buffer pointer. Also, setup 1496 * an array of buffer pointers for the iovec structs record and replace 1497 * their pointers with buffer pointers. 1498 */ 1499 BufferArg *iovBuf = NULL; 1500 BufferArg *iovecBuf[msgHdr->msg_iovlen]; 1501 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1502 iovec_base_phold[i] = 0; 1503 iovecBuf[i] = NULL; 1504 } 1505 1506 if (msgHdr->msg_iov) { 1507 /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov; 1508 /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen * 1509 sizeof(struct iovec)); 1510 /*3*/iovBuf->copyIn(tc->getVirtProxy()); 1511 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1512 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1513 /*1*/iovec_base_phold[i] = 1514 (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base; 1515 /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i], 1516 ((struct iovec *)iovBuf->bufferPtr())[i].iov_len); 1517 /*3*/iovecBuf[i]->copyIn(tc->getVirtProxy()); 1518 /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1519 iovecBuf[i]->bufferPtr(); 1520 } 1521 } 1522 /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr(); 1523 } 1524 1525 /** 1526 * Record msg_control pointer then replace with buffer pointer. 1527 */ 1528 BufferArg *controlBuf = NULL; 1529 if (msgHdr->msg_control) { 1530 /*1*/msg_control_phold = (Addr)msgHdr->msg_control; 1531 /*2*/controlBuf = new BufferArg(msg_control_phold, 1532 CMSG_ALIGN(msgHdr->msg_controllen)); 1533 /*3*/controlBuf->copyIn(tc->getVirtProxy()); 1534 /*4*/msgHdr->msg_control = controlBuf->bufferPtr(); 1535 } 1536 1537 ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags); 1538 1539 if (recvd_size < 0) 1540 return -errno; 1541 1542 if (msgHdr->msg_name) { 1543 nameBuf->copyOut(tc->getVirtProxy()); 1544 delete(nameBuf); 1545 msgHdr->msg_name = (void *)msg_name_phold; 1546 } 1547 1548 if (msgHdr->msg_iov) { 1549 for (int i = 0; i< msgHdr->msg_iovlen; i++) { 1550 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1551 iovecBuf[i]->copyOut(tc->getVirtProxy()); 1552 delete iovecBuf[i]; 1553 ((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1554 (void *)iovec_base_phold[i]; 1555 } 1556 } 1557 iovBuf->copyOut(tc->getVirtProxy()); 1558 delete iovBuf; 1559 msgHdr->msg_iov = (struct iovec *)msg_iov_phold; 1560 } 1561 1562 if (msgHdr->msg_control) { 1563 controlBuf->copyOut(tc->getVirtProxy()); 1564 delete(controlBuf); 1565 msgHdr->msg_control = (void *)msg_control_phold; 1566 } 1567 1568 msgBuf.copyOut(tc->getVirtProxy()); 1569 1570 return recvd_size; 1571} 1572 1573SyscallReturn 1574sendmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1575{ 1576 int index = 0; 1577 auto p = tc->getProcessPtr(); 1578 int tgt_fd = p->getSyscallArg(tc, index); 1579 Addr msgPtr = p->getSyscallArg(tc, index); 1580 int flags = p->getSyscallArg(tc, index); 1581 1582 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1583 if (!sfdp) 1584 return -EBADF; 1585 int sim_fd = sfdp->getSimFD(); 1586 1587 /** 1588 * Reserve buffer space. 1589 */ 1590 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1591 msgBuf.copyIn(tc->getVirtProxy()); 1592 struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr()); 1593 1594 /** 1595 * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling 1596 * recvmsg without a buffer. 1597 */ 1598 struct iovec *iovPtr = msgHdr.msg_iov; 1599 BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen); 1600 iovBuf.copyIn(tc->getVirtProxy()); 1601 struct iovec *iov = (struct iovec *)iovBuf.bufferPtr(); 1602 msgHdr.msg_iov = iov; 1603 1604 /** 1605 * Cannot instantiate buffers till inside the loop. 1606 * Create array to hold buffer addresses, to be used during copyIn of 1607 * send data. 1608 */ 1609 BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen 1610 * sizeof(BufferArg *)); 1611 1612 /** 1613 * Iterate through the iovec structures: 1614 * Get the base buffer addreses, reserve iov_len amount of space for each. 1615 * Put the buf address into the bufferArray for later retrieval. 1616 */ 1617 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1618 Addr basePtr = (Addr) iov[iovIndex].iov_base; 1619 bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len); 1620 bufferArray[iovIndex]->copyIn(tc->getVirtProxy()); 1621 iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr(); 1622 } 1623 1624 ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags); 1625 int local_errno = errno; 1626 1627 /** 1628 * Free dynamically allocated memory. 1629 */ 1630 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1631 BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex]; 1632 delete(baseBuf); 1633 } 1634 1635 /** 1636 * Malloced above. 1637 */ 1638 free(bufferArray); 1639 1640 return (sent_size < 0) ? -local_errno : sent_size; 1641} 1642 1643SyscallReturn 1644getsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1645{ 1646 // union of all possible return value types from getsockopt 1647 union val { 1648 int i_val; 1649 long l_val; 1650 struct linger linger_val; 1651 struct timeval timeval_val; 1652 } val; 1653 1654 int index = 0; 1655 auto p = tc->getProcessPtr(); 1656 int tgt_fd = p->getSyscallArg(tc, index); 1657 int level = p->getSyscallArg(tc, index); 1658 int optname = p->getSyscallArg(tc, index); 1659 Addr valPtr = p->getSyscallArg(tc, index); 1660 Addr lenPtr = p->getSyscallArg(tc, index); 1661 1662 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1663 if (!sfdp) 1664 return -EBADF; 1665 int sim_fd = sfdp->getSimFD(); 1666 1667 socklen_t len = sizeof(val); 1668 int status = getsockopt(sim_fd, level, optname, &val, &len); 1669 1670 if (status == -1) 1671 return -errno; 1672 1673 // copy val to valPtr and pass it on 1674 BufferArg valBuf(valPtr, sizeof(val)); 1675 memcpy(valBuf.bufferPtr(), &val, sizeof(val)); 1676 valBuf.copyOut(tc->getVirtProxy()); 1677 1678 // copy len to lenPtr and pass it on 1679 BufferArg lenBuf(lenPtr, sizeof(len)); 1680 memcpy(lenBuf.bufferPtr(), &len, sizeof(len)); 1681 lenBuf.copyOut(tc->getVirtProxy()); 1682 1683 return status; 1684} 1685 1686SyscallReturn 1687getsocknameFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1688{ 1689 int index = 0; 1690 auto p = tc->getProcessPtr(); 1691 int tgt_fd = p->getSyscallArg(tc, index); 1692 Addr addrPtr = p->getSyscallArg(tc, index); 1693 Addr lenPtr = p->getSyscallArg(tc, index); 1694 1695 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1696 if (!sfdp) 1697 return -EBADF; 1698 int sim_fd = sfdp->getSimFD(); 1699 1700 // lenPtr is an in-out paramenter: 1701 // sending the address length in, conveying the final length out 1702 1703 // Read in the value of len from the passed pointer. 1704 BufferArg lenBuf(lenPtr, sizeof(socklen_t)); 1705 lenBuf.copyIn(tc->getVirtProxy()); 1706 socklen_t len = *(socklen_t *)lenBuf.bufferPtr(); 1707 1708 struct sockaddr sa; 1709 int status = getsockname(sim_fd, &sa, &len); 1710 1711 if (status == -1) 1712 return -errno; 1713 1714 // Copy address to addrPtr and pass it on. 1715 BufferArg addrBuf(addrPtr, sizeof(sa)); 1716 memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa)); 1717 addrBuf.copyOut(tc->getVirtProxy()); 1718 1719 // Copy len to lenPtr and pass it on. 1720 *(socklen_t *)lenBuf.bufferPtr() = len; 1721 lenBuf.copyOut(tc->getVirtProxy()); 1722 1723 return status; 1724} 1725 1726SyscallReturn 1727getpeernameFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1728{ 1729 int index = 0; 1730 auto p = tc->getProcessPtr(); 1731 int tgt_fd = p->getSyscallArg(tc, index); 1732 Addr sockAddrPtr = p->getSyscallArg(tc, index); 1733 Addr addrlenPtr = p->getSyscallArg(tc, index); 1734 1735 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1736 if (!sfdp) 1737 return -EBADF; 1738 int sim_fd = sfdp->getSimFD(); 1739 1740 BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned)); 1741 bufAddrlen.copyIn(tc->getVirtProxy()); 1742 BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr()); 1743 1744 int retval = getpeername(sim_fd, 1745 (struct sockaddr *)bufSock.bufferPtr(), 1746 (unsigned *)bufAddrlen.bufferPtr()); 1747 1748 if (retval != -1) { 1749 bufSock.copyOut(tc->getVirtProxy()); 1750 bufAddrlen.copyOut(tc->getVirtProxy()); 1751 } 1752 1753 return (retval == -1) ? -errno : retval; 1754} 1755 1756SyscallReturn 1757setsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1758{ 1759 int index = 0; 1760 auto p = tc->getProcessPtr(); 1761 int tgt_fd = p->getSyscallArg(tc, index); 1762 int level = p->getSyscallArg(tc, index); 1763 int optname = p->getSyscallArg(tc, index); 1764 Addr valPtr = p->getSyscallArg(tc, index); 1765 socklen_t len = p->getSyscallArg(tc, index); 1766 1767 BufferArg valBuf(valPtr, len); 1768 valBuf.copyIn(tc->getVirtProxy()); 1769 1770 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1771 if (!sfdp) 1772 return -EBADF; 1773 int sim_fd = sfdp->getSimFD(); 1774 1775 int status = setsockopt(sim_fd, level, optname, 1776 (struct sockaddr *)valBuf.bufferPtr(), len); 1777 1778 return (status == -1) ? -errno : status; 1779} 1780 1781