syscall_emul.cc revision 13995
112027Sjungma@eit.uni-kl.de/* 212027Sjungma@eit.uni-kl.de * Copyright (c) 2003-2005 The Regents of The University of Michigan 312027Sjungma@eit.uni-kl.de * All rights reserved. 412027Sjungma@eit.uni-kl.de * 512027Sjungma@eit.uni-kl.de * Redistribution and use in source and binary forms, with or without 612027Sjungma@eit.uni-kl.de * modification, are permitted provided that the following conditions are 712027Sjungma@eit.uni-kl.de * met: redistributions of source code must retain the above copyright 812027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer; 912027Sjungma@eit.uni-kl.de * redistributions in binary form must reproduce the above copyright 1012027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer in the 1112027Sjungma@eit.uni-kl.de * documentation and/or other materials provided with the distribution; 1212027Sjungma@eit.uni-kl.de * neither the name of the copyright holders nor the names of its 1312027Sjungma@eit.uni-kl.de * contributors may be used to endorse or promote products derived from 1412027Sjungma@eit.uni-kl.de * this software without specific prior written permission. 1512027Sjungma@eit.uni-kl.de * 1612027Sjungma@eit.uni-kl.de * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712027Sjungma@eit.uni-kl.de * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812027Sjungma@eit.uni-kl.de * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912027Sjungma@eit.uni-kl.de * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012027Sjungma@eit.uni-kl.de * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112027Sjungma@eit.uni-kl.de * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212027Sjungma@eit.uni-kl.de * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312027Sjungma@eit.uni-kl.de * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412027Sjungma@eit.uni-kl.de * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512027Sjungma@eit.uni-kl.de * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612027Sjungma@eit.uni-kl.de * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712027Sjungma@eit.uni-kl.de * 2812027Sjungma@eit.uni-kl.de * Authors: Steve Reinhardt 2912027Sjungma@eit.uni-kl.de * Ali Saidi 3012027Sjungma@eit.uni-kl.de */ 3112027Sjungma@eit.uni-kl.de 3212027Sjungma@eit.uni-kl.de#include "sim/syscall_emul.hh" 3312027Sjungma@eit.uni-kl.de 3412027Sjungma@eit.uni-kl.de#include <fcntl.h> 3512027Sjungma@eit.uni-kl.de#include <sys/syscall.h> 3612027Sjungma@eit.uni-kl.de#include <unistd.h> 3712027Sjungma@eit.uni-kl.de 3812027Sjungma@eit.uni-kl.de#include <csignal> 3912027Sjungma@eit.uni-kl.de#include <iostream> 4012027Sjungma@eit.uni-kl.de#include <mutex> 4112027Sjungma@eit.uni-kl.de#include <string> 4212027Sjungma@eit.uni-kl.de 4312027Sjungma@eit.uni-kl.de#include "arch/utility.hh" 4412027Sjungma@eit.uni-kl.de#include "base/chunk_generator.hh" 4512027Sjungma@eit.uni-kl.de#include "base/trace.hh" 4612027Sjungma@eit.uni-kl.de#include "config/the_isa.hh" 4712027Sjungma@eit.uni-kl.de#include "cpu/thread_context.hh" 4812027Sjungma@eit.uni-kl.de#include "dev/net/dist_iface.hh" 4912027Sjungma@eit.uni-kl.de#include "mem/page_table.hh" 5012027Sjungma@eit.uni-kl.de#include "sim/byteswap.hh" 5112027Sjungma@eit.uni-kl.de#include "sim/process.hh" 5212027Sjungma@eit.uni-kl.de#include "sim/sim_exit.hh" 5312027Sjungma@eit.uni-kl.de#include "sim/syscall_debug_macros.hh" 5412027Sjungma@eit.uni-kl.de#include "sim/syscall_desc.hh" 5512027Sjungma@eit.uni-kl.de#include "sim/system.hh" 5612027Sjungma@eit.uni-kl.de 5712027Sjungma@eit.uni-kl.deusing namespace std; 5812027Sjungma@eit.uni-kl.deusing namespace TheISA; 5912027Sjungma@eit.uni-kl.de 6012027Sjungma@eit.uni-kl.devoid 6112027Sjungma@eit.uni-kl.dewarnUnsupportedOS(std::string syscall_name) 6212027Sjungma@eit.uni-kl.de{ 6312027Sjungma@eit.uni-kl.de warn("Cannot invoke %s on host operating system.", syscall_name); 6412027Sjungma@eit.uni-kl.de} 6512027Sjungma@eit.uni-kl.de 6612027Sjungma@eit.uni-kl.deSyscallReturn 6712027Sjungma@eit.uni-kl.deunimplementedFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 6812027Sjungma@eit.uni-kl.de{ 6912027Sjungma@eit.uni-kl.de fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum); 7012027Sjungma@eit.uni-kl.de 7112027Sjungma@eit.uni-kl.de return 1; 7212027Sjungma@eit.uni-kl.de} 7312027Sjungma@eit.uni-kl.de 7412027Sjungma@eit.uni-kl.de 7512027Sjungma@eit.uni-kl.deSyscallReturn 7612027Sjungma@eit.uni-kl.deignoreFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 7712027Sjungma@eit.uni-kl.de{ 7812027Sjungma@eit.uni-kl.de if (desc->needWarning()) { 7912027Sjungma@eit.uni-kl.de warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ? 8012027Sjungma@eit.uni-kl.de "\n (further warnings will be suppressed)" : ""); 8112027Sjungma@eit.uni-kl.de } 8212027Sjungma@eit.uni-kl.de 8312027Sjungma@eit.uni-kl.de return 0; 8412027Sjungma@eit.uni-kl.de} 8512027Sjungma@eit.uni-kl.de 8612027Sjungma@eit.uni-kl.destatic void 8712027Sjungma@eit.uni-kl.deexitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid) 8812027Sjungma@eit.uni-kl.de{ 8912027Sjungma@eit.uni-kl.de // Clear value at address pointed to by thread's childClearTID field. 9012027Sjungma@eit.uni-kl.de BufferArg ctidBuf(addr, sizeof(long)); 9112027Sjungma@eit.uni-kl.de long *ctid = (long *)ctidBuf.bufferPtr(); 9212027Sjungma@eit.uni-kl.de *ctid = 0; 9312027Sjungma@eit.uni-kl.de ctidBuf.copyOut(tc->getMemProxy()); 9412027Sjungma@eit.uni-kl.de 9512027Sjungma@eit.uni-kl.de FutexMap &futex_map = tc->getSystemPtr()->futexMap; 9612027Sjungma@eit.uni-kl.de // Wake one of the waiting threads. 9712027Sjungma@eit.uni-kl.de futex_map.wakeup(addr, tgid, 1); 9812027Sjungma@eit.uni-kl.de} 9912027Sjungma@eit.uni-kl.de 10012027Sjungma@eit.uni-kl.destatic SyscallReturn 10112027Sjungma@eit.uni-kl.deexitImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool group) 10212027Sjungma@eit.uni-kl.de{ 10312027Sjungma@eit.uni-kl.de int index = 0; 10412027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 10512027Sjungma@eit.uni-kl.de int status = p->getSyscallArg(tc, index); 10612027Sjungma@eit.uni-kl.de 10712027Sjungma@eit.uni-kl.de System *sys = tc->getSystemPtr(); 10812027Sjungma@eit.uni-kl.de 10912027Sjungma@eit.uni-kl.de if (group) 11012027Sjungma@eit.uni-kl.de *p->exitGroup = true; 11112027Sjungma@eit.uni-kl.de 11212027Sjungma@eit.uni-kl.de if (p->childClearTID) 11312027Sjungma@eit.uni-kl.de exitFutexWake(tc, p->childClearTID, p->tgid()); 11412027Sjungma@eit.uni-kl.de 11512027Sjungma@eit.uni-kl.de bool last_thread = true; 11612027Sjungma@eit.uni-kl.de Process *parent = nullptr, *tg_lead = nullptr; 11712027Sjungma@eit.uni-kl.de for (int i = 0; last_thread && i < sys->numContexts(); i++) { 11812027Sjungma@eit.uni-kl.de Process *walk; 11912027Sjungma@eit.uni-kl.de if (!(walk = sys->threadContexts[i]->getProcessPtr())) 12012027Sjungma@eit.uni-kl.de continue; 12112027Sjungma@eit.uni-kl.de 12212027Sjungma@eit.uni-kl.de /** 12312027Sjungma@eit.uni-kl.de * Threads in a thread group require special handing. For instance, 12412027Sjungma@eit.uni-kl.de * we send the SIGCHLD signal so that it appears that it came from 12512027Sjungma@eit.uni-kl.de * the head of the group. We also only delete file descriptors if 12612027Sjungma@eit.uni-kl.de * we are the last thread in the thread group. 12712027Sjungma@eit.uni-kl.de */ 12812027Sjungma@eit.uni-kl.de if (walk->pid() == p->tgid()) 12912027Sjungma@eit.uni-kl.de tg_lead = walk; 13012027Sjungma@eit.uni-kl.de 13112027Sjungma@eit.uni-kl.de if ((sys->threadContexts[i]->status() != ThreadContext::Halted) && 13212027Sjungma@eit.uni-kl.de (sys->threadContexts[i]->status() != ThreadContext::Halting) && 13312027Sjungma@eit.uni-kl.de (walk != p)) { 13412027Sjungma@eit.uni-kl.de /** 13512027Sjungma@eit.uni-kl.de * Check if we share thread group with the pointer; this denotes 13612027Sjungma@eit.uni-kl.de * that we are not the last thread active in the thread group. 13712027Sjungma@eit.uni-kl.de * Note that setting this to false also prevents further 13812027Sjungma@eit.uni-kl.de * iterations of the loop. 13912027Sjungma@eit.uni-kl.de */ 14012027Sjungma@eit.uni-kl.de if (walk->tgid() == p->tgid()) { 14112027Sjungma@eit.uni-kl.de /** 14212027Sjungma@eit.uni-kl.de * If p is trying to exit_group and both walk and p are in 14312027Sjungma@eit.uni-kl.de * the same thread group (i.e., sharing the same tgid), 14412027Sjungma@eit.uni-kl.de * we need to halt walk's thread context. After all threads 14512027Sjungma@eit.uni-kl.de * except p are halted, p becomes the last thread in the 14612027Sjungma@eit.uni-kl.de * group. 14712027Sjungma@eit.uni-kl.de * 14812027Sjungma@eit.uni-kl.de * If p is not doing exit_group and there exists another 14912027Sjungma@eit.uni-kl.de * active thread context in the group, last_thread is 15012027Sjungma@eit.uni-kl.de * set to false to prevent the parent thread from killing 15112027Sjungma@eit.uni-kl.de * all threads in the group. 15212027Sjungma@eit.uni-kl.de */ 15312027Sjungma@eit.uni-kl.de if (*(p->exitGroup)) { 15412027Sjungma@eit.uni-kl.de sys->threadContexts[i]->halt(); 15512027Sjungma@eit.uni-kl.de } else { 15612027Sjungma@eit.uni-kl.de last_thread = false; 15712027Sjungma@eit.uni-kl.de } 15812027Sjungma@eit.uni-kl.de } 15912027Sjungma@eit.uni-kl.de 16012027Sjungma@eit.uni-kl.de /** 16112027Sjungma@eit.uni-kl.de * A corner case exists which involves execve(). After execve(), 16212027Sjungma@eit.uni-kl.de * the execve will enable SIGCHLD in the process. The problem 16312027Sjungma@eit.uni-kl.de * occurs when the exiting process is the root process in the 16412027Sjungma@eit.uni-kl.de * system; there is no parent to receive the signal. We obviate 16512027Sjungma@eit.uni-kl.de * this problem by setting the root process' ppid to zero in the 16612027Sjungma@eit.uni-kl.de * Python configuration files. We really should handle the 16712027Sjungma@eit.uni-kl.de * root/execve specific case more gracefully. 16812027Sjungma@eit.uni-kl.de */ 16912027Sjungma@eit.uni-kl.de if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid())) 17012027Sjungma@eit.uni-kl.de parent = walk; 17112027Sjungma@eit.uni-kl.de } 17212027Sjungma@eit.uni-kl.de } 17312027Sjungma@eit.uni-kl.de 17412027Sjungma@eit.uni-kl.de if (last_thread) { 17512027Sjungma@eit.uni-kl.de if (parent) { 17612027Sjungma@eit.uni-kl.de assert(tg_lead); 17712027Sjungma@eit.uni-kl.de sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD)); 17812027Sjungma@eit.uni-kl.de } 17912027Sjungma@eit.uni-kl.de 18012027Sjungma@eit.uni-kl.de /** 18112027Sjungma@eit.uni-kl.de * Run though FD array of the exiting process and close all file 18212027Sjungma@eit.uni-kl.de * descriptors except for the standard file descriptors. 18312027Sjungma@eit.uni-kl.de * (The standard file descriptors are shared with gem5.) 18412027Sjungma@eit.uni-kl.de */ 18512027Sjungma@eit.uni-kl.de for (int i = 0; i < p->fds->getSize(); i++) { 18612027Sjungma@eit.uni-kl.de if ((*p->fds)[i]) 18712027Sjungma@eit.uni-kl.de p->fds->closeFDEntry(i); 18812027Sjungma@eit.uni-kl.de } 18912027Sjungma@eit.uni-kl.de } 19012027Sjungma@eit.uni-kl.de 19112027Sjungma@eit.uni-kl.de tc->halt(); 19212027Sjungma@eit.uni-kl.de 19312027Sjungma@eit.uni-kl.de /** 19412027Sjungma@eit.uni-kl.de * check to see if there is no more active thread in the system. If so, 19512027Sjungma@eit.uni-kl.de * exit the simulation loop 19612027Sjungma@eit.uni-kl.de */ 19712027Sjungma@eit.uni-kl.de int activeContexts = 0; 19812027Sjungma@eit.uni-kl.de for (auto &system: sys->systemList) 19912027Sjungma@eit.uni-kl.de activeContexts += system->numRunningContexts(); 20012027Sjungma@eit.uni-kl.de 20112027Sjungma@eit.uni-kl.de if (activeContexts == 0) { 20212027Sjungma@eit.uni-kl.de /** 20312027Sjungma@eit.uni-kl.de * Even though we are terminating the final thread context, dist-gem5 20412027Sjungma@eit.uni-kl.de * requires the simulation to remain active and provide 20512027Sjungma@eit.uni-kl.de * synchronization messages to the switch process. So we just halt 20612027Sjungma@eit.uni-kl.de * the last thread context and return. The simulation will be 20712027Sjungma@eit.uni-kl.de * terminated by dist-gem5 in a coordinated manner once all nodes 20812027Sjungma@eit.uni-kl.de * have signaled their readiness to exit. For non dist-gem5 20912027Sjungma@eit.uni-kl.de * simulations, readyToExit() always returns true. 21012027Sjungma@eit.uni-kl.de */ 21112027Sjungma@eit.uni-kl.de if (!DistIface::readyToExit(0)) { 21212027Sjungma@eit.uni-kl.de return status; 21312027Sjungma@eit.uni-kl.de } 21412027Sjungma@eit.uni-kl.de 21512027Sjungma@eit.uni-kl.de exitSimLoop("exiting with last active thread context", status & 0xff); 21612027Sjungma@eit.uni-kl.de return status; 21712027Sjungma@eit.uni-kl.de } 21812027Sjungma@eit.uni-kl.de 21912027Sjungma@eit.uni-kl.de return status; 22012027Sjungma@eit.uni-kl.de} 22112027Sjungma@eit.uni-kl.de 22212027Sjungma@eit.uni-kl.deSyscallReturn 22312027Sjungma@eit.uni-kl.deexitFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 22412027Sjungma@eit.uni-kl.de{ 22512027Sjungma@eit.uni-kl.de return exitImpl(desc, callnum, tc, false); 22612027Sjungma@eit.uni-kl.de} 22712027Sjungma@eit.uni-kl.de 22812027Sjungma@eit.uni-kl.deSyscallReturn 22912027Sjungma@eit.uni-kl.deexitGroupFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 23012027Sjungma@eit.uni-kl.de{ 23112027Sjungma@eit.uni-kl.de return exitImpl(desc, callnum, tc, true); 23212027Sjungma@eit.uni-kl.de} 23312027Sjungma@eit.uni-kl.de 23412027Sjungma@eit.uni-kl.deSyscallReturn 23512027Sjungma@eit.uni-kl.degetpagesizeFunc(SyscallDesc *desc, int num, ThreadContext *tc) 23612027Sjungma@eit.uni-kl.de{ 23712027Sjungma@eit.uni-kl.de return (int)PageBytes; 23812027Sjungma@eit.uni-kl.de} 23912027Sjungma@eit.uni-kl.de 24012027Sjungma@eit.uni-kl.de 24112027Sjungma@eit.uni-kl.deSyscallReturn 24212027Sjungma@eit.uni-kl.debrkFunc(SyscallDesc *desc, int num, ThreadContext *tc) 24312027Sjungma@eit.uni-kl.de{ 24412027Sjungma@eit.uni-kl.de // change brk addr to first arg 24512027Sjungma@eit.uni-kl.de int index = 0; 24612027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 24712027Sjungma@eit.uni-kl.de Addr new_brk = p->getSyscallArg(tc, index); 24812027Sjungma@eit.uni-kl.de 24912027Sjungma@eit.uni-kl.de std::shared_ptr<MemState> mem_state = p->memState; 25012027Sjungma@eit.uni-kl.de Addr brk_point = mem_state->getBrkPoint(); 25112027Sjungma@eit.uni-kl.de 25212027Sjungma@eit.uni-kl.de // in Linux at least, brk(0) returns the current break value 25312027Sjungma@eit.uni-kl.de // (note that the syscall and the glibc function have different behavior) 25412027Sjungma@eit.uni-kl.de if (new_brk == 0) 25512027Sjungma@eit.uni-kl.de return brk_point; 25612027Sjungma@eit.uni-kl.de 25712027Sjungma@eit.uni-kl.de if (new_brk > brk_point) { 25812027Sjungma@eit.uni-kl.de // might need to allocate some new pages 25912027Sjungma@eit.uni-kl.de for (ChunkGenerator gen(brk_point, 26012027Sjungma@eit.uni-kl.de new_brk - brk_point, 26112027Sjungma@eit.uni-kl.de PageBytes); !gen.done(); gen.next()) { 26212027Sjungma@eit.uni-kl.de if (!p->pTable->translate(gen.addr())) 26312027Sjungma@eit.uni-kl.de p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 26412027Sjungma@eit.uni-kl.de 26512027Sjungma@eit.uni-kl.de // if the address is already there, zero it out 26612027Sjungma@eit.uni-kl.de else { 26712027Sjungma@eit.uni-kl.de uint8_t zero = 0; 26812027Sjungma@eit.uni-kl.de SETranslatingPortProxy &tp = tc->getMemProxy(); 26912027Sjungma@eit.uni-kl.de 27012027Sjungma@eit.uni-kl.de // split non-page aligned accesses 27112027Sjungma@eit.uni-kl.de Addr next_page = roundUp(gen.addr(), PageBytes); 27212027Sjungma@eit.uni-kl.de uint32_t size_needed = next_page - gen.addr(); 27312027Sjungma@eit.uni-kl.de tp.memsetBlob(gen.addr(), zero, size_needed); 27412027Sjungma@eit.uni-kl.de if (gen.addr() + PageBytes > next_page && 27512027Sjungma@eit.uni-kl.de next_page < new_brk && 27612027Sjungma@eit.uni-kl.de p->pTable->translate(next_page)) { 27712027Sjungma@eit.uni-kl.de size_needed = PageBytes - size_needed; 27812027Sjungma@eit.uni-kl.de tp.memsetBlob(next_page, zero, size_needed); 27912027Sjungma@eit.uni-kl.de } 28012027Sjungma@eit.uni-kl.de } 28112027Sjungma@eit.uni-kl.de } 28212027Sjungma@eit.uni-kl.de } 28312027Sjungma@eit.uni-kl.de 28412027Sjungma@eit.uni-kl.de mem_state->setBrkPoint(new_brk); 28512027Sjungma@eit.uni-kl.de DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 28612027Sjungma@eit.uni-kl.de mem_state->getBrkPoint()); 28712027Sjungma@eit.uni-kl.de return mem_state->getBrkPoint(); 28812027Sjungma@eit.uni-kl.de} 28912027Sjungma@eit.uni-kl.de 29012027Sjungma@eit.uni-kl.deSyscallReturn 29112027Sjungma@eit.uni-kl.desetTidAddressFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 29212027Sjungma@eit.uni-kl.de{ 29312027Sjungma@eit.uni-kl.de int index = 0; 29412027Sjungma@eit.uni-kl.de auto process = tc->getProcessPtr(); 29512027Sjungma@eit.uni-kl.de uint64_t tidPtr = process->getSyscallArg(tc, index); 29612027Sjungma@eit.uni-kl.de 29712027Sjungma@eit.uni-kl.de process->childClearTID = tidPtr; 29812027Sjungma@eit.uni-kl.de return process->pid(); 29912027Sjungma@eit.uni-kl.de} 30012027Sjungma@eit.uni-kl.de 30112027Sjungma@eit.uni-kl.deSyscallReturn 30212027Sjungma@eit.uni-kl.decloseFunc(SyscallDesc *desc, int num, ThreadContext *tc) 30312027Sjungma@eit.uni-kl.de{ 30412027Sjungma@eit.uni-kl.de int index = 0; 30512027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 30612027Sjungma@eit.uni-kl.de int tgt_fd = p->getSyscallArg(tc, index); 30712027Sjungma@eit.uni-kl.de 30812027Sjungma@eit.uni-kl.de return p->fds->closeFDEntry(tgt_fd); 30912027Sjungma@eit.uni-kl.de} 31012027Sjungma@eit.uni-kl.de 31112027Sjungma@eit.uni-kl.deSyscallReturn 31212027Sjungma@eit.uni-kl.delseekFunc(SyscallDesc *desc, int num, ThreadContext *tc) 31312027Sjungma@eit.uni-kl.de{ 31412027Sjungma@eit.uni-kl.de int index = 0; 31512027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 31612027Sjungma@eit.uni-kl.de int tgt_fd = p->getSyscallArg(tc, index); 31712027Sjungma@eit.uni-kl.de uint64_t offs = p->getSyscallArg(tc, index); 31812027Sjungma@eit.uni-kl.de int whence = p->getSyscallArg(tc, index); 31912027Sjungma@eit.uni-kl.de 32012027Sjungma@eit.uni-kl.de auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 32112027Sjungma@eit.uni-kl.de if (!ffdp) 32212027Sjungma@eit.uni-kl.de return -EBADF; 32312027Sjungma@eit.uni-kl.de int sim_fd = ffdp->getSimFD(); 32412027Sjungma@eit.uni-kl.de 32512027Sjungma@eit.uni-kl.de off_t result = lseek(sim_fd, offs, whence); 32612027Sjungma@eit.uni-kl.de 32712027Sjungma@eit.uni-kl.de return (result == (off_t)-1) ? -errno : result; 32812027Sjungma@eit.uni-kl.de} 32912027Sjungma@eit.uni-kl.de 33012027Sjungma@eit.uni-kl.de 33112027Sjungma@eit.uni-kl.deSyscallReturn 33212027Sjungma@eit.uni-kl.de_llseekFunc(SyscallDesc *desc, int num, ThreadContext *tc) 33312027Sjungma@eit.uni-kl.de{ 33412027Sjungma@eit.uni-kl.de int index = 0; 33512027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 33612027Sjungma@eit.uni-kl.de int tgt_fd = p->getSyscallArg(tc, index); 33712027Sjungma@eit.uni-kl.de uint64_t offset_high = p->getSyscallArg(tc, index); 33812027Sjungma@eit.uni-kl.de uint32_t offset_low = p->getSyscallArg(tc, index); 33912027Sjungma@eit.uni-kl.de Addr result_ptr = p->getSyscallArg(tc, index); 34012027Sjungma@eit.uni-kl.de int whence = p->getSyscallArg(tc, index); 34112027Sjungma@eit.uni-kl.de 34212027Sjungma@eit.uni-kl.de auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 34312027Sjungma@eit.uni-kl.de if (!ffdp) 34412027Sjungma@eit.uni-kl.de return -EBADF; 34512027Sjungma@eit.uni-kl.de int sim_fd = ffdp->getSimFD(); 34612027Sjungma@eit.uni-kl.de 34712027Sjungma@eit.uni-kl.de uint64_t offset = (offset_high << 32) | offset_low; 34812027Sjungma@eit.uni-kl.de 34912027Sjungma@eit.uni-kl.de uint64_t result = lseek(sim_fd, offset, whence); 35012027Sjungma@eit.uni-kl.de result = TheISA::htog(result); 35112027Sjungma@eit.uni-kl.de 35212027Sjungma@eit.uni-kl.de if (result == (off_t)-1) 35312027Sjungma@eit.uni-kl.de return -errno; 35412027Sjungma@eit.uni-kl.de // Assuming that the size of loff_t is 64 bits on the target platform 35512027Sjungma@eit.uni-kl.de BufferArg result_buf(result_ptr, sizeof(result)); 35612027Sjungma@eit.uni-kl.de memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 35712027Sjungma@eit.uni-kl.de result_buf.copyOut(tc->getMemProxy()); 35812027Sjungma@eit.uni-kl.de return 0; 35912027Sjungma@eit.uni-kl.de} 36012027Sjungma@eit.uni-kl.de 36112027Sjungma@eit.uni-kl.de 36212027Sjungma@eit.uni-kl.deSyscallReturn 36312027Sjungma@eit.uni-kl.demunmapFunc(SyscallDesc *desc, int num, ThreadContext *tc) 36412027Sjungma@eit.uni-kl.de{ 36512027Sjungma@eit.uni-kl.de // With mmap more fully implemented, it might be worthwhile to bite 36612027Sjungma@eit.uni-kl.de // the bullet and implement munmap. Should allow us to reuse simulated 36712027Sjungma@eit.uni-kl.de // memory. 36812027Sjungma@eit.uni-kl.de return 0; 36912027Sjungma@eit.uni-kl.de} 37012027Sjungma@eit.uni-kl.de 37112027Sjungma@eit.uni-kl.de 37212027Sjungma@eit.uni-kl.deconst char *hostname = "m5.eecs.umich.edu"; 37312027Sjungma@eit.uni-kl.de 37412027Sjungma@eit.uni-kl.deSyscallReturn 37512027Sjungma@eit.uni-kl.degethostnameFunc(SyscallDesc *desc, int num, ThreadContext *tc) 37612027Sjungma@eit.uni-kl.de{ 37712027Sjungma@eit.uni-kl.de int index = 0; 37812027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 37912027Sjungma@eit.uni-kl.de Addr buf_ptr = p->getSyscallArg(tc, index); 38012027Sjungma@eit.uni-kl.de int name_len = p->getSyscallArg(tc, index); 38112027Sjungma@eit.uni-kl.de BufferArg name(buf_ptr, name_len); 38212027Sjungma@eit.uni-kl.de 38312027Sjungma@eit.uni-kl.de strncpy((char *)name.bufferPtr(), hostname, name_len); 38412027Sjungma@eit.uni-kl.de 38512027Sjungma@eit.uni-kl.de name.copyOut(tc->getMemProxy()); 38612027Sjungma@eit.uni-kl.de 38712027Sjungma@eit.uni-kl.de return 0; 38812027Sjungma@eit.uni-kl.de} 38912027Sjungma@eit.uni-kl.de 39012027Sjungma@eit.uni-kl.deSyscallReturn 39112027Sjungma@eit.uni-kl.degetcwdFunc(SyscallDesc *desc, int num, ThreadContext *tc) 39212027Sjungma@eit.uni-kl.de{ 39312027Sjungma@eit.uni-kl.de int result = 0; 39412027Sjungma@eit.uni-kl.de int index = 0; 39512027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 39612027Sjungma@eit.uni-kl.de Addr buf_ptr = p->getSyscallArg(tc, index); 39712027Sjungma@eit.uni-kl.de unsigned long size = p->getSyscallArg(tc, index); 39812027Sjungma@eit.uni-kl.de BufferArg buf(buf_ptr, size); 39912027Sjungma@eit.uni-kl.de 40012027Sjungma@eit.uni-kl.de // Is current working directory defined? 40112027Sjungma@eit.uni-kl.de string cwd = p->tgtCwd; 40212027Sjungma@eit.uni-kl.de if (!cwd.empty()) { 40312027Sjungma@eit.uni-kl.de if (cwd.length() >= size) { 40412027Sjungma@eit.uni-kl.de // Buffer too small 40512027Sjungma@eit.uni-kl.de return -ERANGE; 40612027Sjungma@eit.uni-kl.de } 40712027Sjungma@eit.uni-kl.de strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 40812027Sjungma@eit.uni-kl.de result = cwd.length(); 40912027Sjungma@eit.uni-kl.de } else { 41012027Sjungma@eit.uni-kl.de if (getcwd((char *)buf.bufferPtr(), size)) { 41112027Sjungma@eit.uni-kl.de result = strlen((char *)buf.bufferPtr()); 41212027Sjungma@eit.uni-kl.de } else { 41312027Sjungma@eit.uni-kl.de result = -1; 41412027Sjungma@eit.uni-kl.de } 41512027Sjungma@eit.uni-kl.de } 41612027Sjungma@eit.uni-kl.de 41712027Sjungma@eit.uni-kl.de buf.copyOut(tc->getMemProxy()); 41812027Sjungma@eit.uni-kl.de 41912027Sjungma@eit.uni-kl.de return (result == -1) ? -errno : result; 42012027Sjungma@eit.uni-kl.de} 42112027Sjungma@eit.uni-kl.de 42212027Sjungma@eit.uni-kl.deSyscallReturn 42312027Sjungma@eit.uni-kl.dereadlinkFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 42412027Sjungma@eit.uni-kl.de{ 42512027Sjungma@eit.uni-kl.de return readlinkFunc(desc, callnum, tc, 0); 42612027Sjungma@eit.uni-kl.de} 42712027Sjungma@eit.uni-kl.de 42812027Sjungma@eit.uni-kl.deSyscallReturn 42912027Sjungma@eit.uni-kl.dereadlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc, int index) 43012027Sjungma@eit.uni-kl.de{ 43112027Sjungma@eit.uni-kl.de string path; 43212027Sjungma@eit.uni-kl.de auto p = tc->getProcessPtr(); 43312027Sjungma@eit.uni-kl.de 43412027Sjungma@eit.uni-kl.de if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 43512027Sjungma@eit.uni-kl.de return -EFAULT; 43612027Sjungma@eit.uni-kl.de 43712027Sjungma@eit.uni-kl.de // Adjust path for cwd and redirection 43812027Sjungma@eit.uni-kl.de path = p->checkPathRedirect(path); 43912027Sjungma@eit.uni-kl.de 44012027Sjungma@eit.uni-kl.de Addr buf_ptr = p->getSyscallArg(tc, index); 44112027Sjungma@eit.uni-kl.de size_t bufsiz = p->getSyscallArg(tc, index); 44212027Sjungma@eit.uni-kl.de 44312027Sjungma@eit.uni-kl.de BufferArg buf(buf_ptr, bufsiz); 44412027Sjungma@eit.uni-kl.de 44512027Sjungma@eit.uni-kl.de int result = -1; 44612027Sjungma@eit.uni-kl.de if (path != "/proc/self/exe") { 44712027Sjungma@eit.uni-kl.de result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 44812027Sjungma@eit.uni-kl.de } else { 44912027Sjungma@eit.uni-kl.de // Emulate readlink() called on '/proc/self/exe' should return the 45012027Sjungma@eit.uni-kl.de // absolute path of the binary running in the simulated system (the 45112027Sjungma@eit.uni-kl.de // Process' executable). It is possible that using this path in 45212027Sjungma@eit.uni-kl.de // the simulated system will result in unexpected behavior if: 45312027Sjungma@eit.uni-kl.de // 1) One binary runs another (e.g., -c time -o "my_binary"), and 45412027Sjungma@eit.uni-kl.de // called binary calls readlink(). 45512027Sjungma@eit.uni-kl.de // 2) The host's full path to the running benchmark changes from one 45612027Sjungma@eit.uni-kl.de // simulation to another. This can result in different simulated 45712027Sjungma@eit.uni-kl.de // performance since the simulated system will process the binary 45812027Sjungma@eit.uni-kl.de // path differently, even if the binary itself does not change. 45912027Sjungma@eit.uni-kl.de 46012027Sjungma@eit.uni-kl.de // Get the absolute canonical path to the running application 46112027Sjungma@eit.uni-kl.de char real_path[PATH_MAX]; 46212027Sjungma@eit.uni-kl.de char *check_real_path = realpath(p->progName(), real_path); 46312027Sjungma@eit.uni-kl.de if (!check_real_path) { 46412027Sjungma@eit.uni-kl.de fatal("readlink('/proc/self/exe') unable to resolve path to " 46512027Sjungma@eit.uni-kl.de "executable: %s", p->progName()); 46612027Sjungma@eit.uni-kl.de } 46712027Sjungma@eit.uni-kl.de strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 468 size_t real_path_len = strlen(real_path); 469 if (real_path_len > bufsiz) { 470 // readlink will truncate the contents of the 471 // path to ensure it is no more than bufsiz 472 result = bufsiz; 473 } else { 474 result = real_path_len; 475 } 476 477 // Issue a warning about potential unexpected results 478 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 479 "results in various settings.\n Returning '%s'\n", 480 (char*)buf.bufferPtr()); 481 } 482 483 buf.copyOut(tc->getMemProxy()); 484 485 return (result == -1) ? -errno : result; 486} 487 488SyscallReturn 489unlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc) 490{ 491 return unlinkHelper(desc, num, tc, 0); 492} 493 494SyscallReturn 495unlinkHelper(SyscallDesc *desc, int num, ThreadContext *tc, int index) 496{ 497 string path; 498 auto p = tc->getProcessPtr(); 499 500 if (!tc->getMemProxy().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->getMemProxy(); 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->getMemProxy(); 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->getMemProxy().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->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 575 return -EFAULT; 576 577 string new_name; 578 579 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 580 return -EFAULT; 581 582 // Adjust path for cwd and redirection 583 old_name = p->checkPathRedirect(old_name); 584 new_name = p->checkPathRedirect(new_name); 585 586 int64_t result = rename(old_name.c_str(), new_name.c_str()); 587 return (result == -1) ? -errno : result; 588} 589 590SyscallReturn 591truncateFunc(SyscallDesc *desc, int num, ThreadContext *tc) 592{ 593 string path; 594 auto p = tc->getProcessPtr(); 595 596 int index = 0; 597 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 598 return -EFAULT; 599 600 off_t length = p->getSyscallArg(tc, index); 601 602 // Adjust path for cwd and redirection 603 path = p->checkPathRedirect(path); 604 605 int result = truncate(path.c_str(), length); 606 return (result == -1) ? -errno : result; 607} 608 609SyscallReturn 610ftruncateFunc(SyscallDesc *desc, int num, ThreadContext *tc) 611{ 612 int index = 0; 613 auto p = tc->getProcessPtr(); 614 int tgt_fd = p->getSyscallArg(tc, index); 615 off_t length = p->getSyscallArg(tc, index); 616 617 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 618 if (!ffdp) 619 return -EBADF; 620 int sim_fd = ffdp->getSimFD(); 621 622 int result = ftruncate(sim_fd, length); 623 return (result == -1) ? -errno : result; 624} 625 626SyscallReturn 627truncate64Func(SyscallDesc *desc, int num, ThreadContext *tc) 628{ 629 int index = 0; 630 auto process = tc->getProcessPtr(); 631 string path; 632 633 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 634 return -EFAULT; 635 636 int64_t length = process->getSyscallArg(tc, index, 64); 637 638 // Adjust path for cwd and redirection 639 path = process->checkPathRedirect(path); 640 641#if NO_STAT64 642 int result = truncate(path.c_str(), length); 643#else 644 int result = truncate64(path.c_str(), length); 645#endif 646 return (result == -1) ? -errno : result; 647} 648 649SyscallReturn 650ftruncate64Func(SyscallDesc *desc, int num, ThreadContext *tc) 651{ 652 int index = 0; 653 auto p = tc->getProcessPtr(); 654 int tgt_fd = p->getSyscallArg(tc, index); 655 int64_t length = p->getSyscallArg(tc, index, 64); 656 657 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 658 if (!ffdp) 659 return -EBADF; 660 int sim_fd = ffdp->getSimFD(); 661 662#if NO_STAT64 663 int result = ftruncate(sim_fd, length); 664#else 665 int result = ftruncate64(sim_fd, length); 666#endif 667 return (result == -1) ? -errno : result; 668} 669 670SyscallReturn 671umaskFunc(SyscallDesc *desc, int num, ThreadContext *tc) 672{ 673 // Letting the simulated program change the simulator's umask seems like 674 // a bad idea. Compromise by just returning the current umask but not 675 // changing anything. 676 mode_t oldMask = umask(0); 677 umask(oldMask); 678 return (int)oldMask; 679} 680 681SyscallReturn 682chownFunc(SyscallDesc *desc, int num, ThreadContext *tc) 683{ 684 string path; 685 auto p = tc->getProcessPtr(); 686 687 int index = 0; 688 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 689 return -EFAULT; 690 691 /* XXX endianess */ 692 uint32_t owner = p->getSyscallArg(tc, index); 693 uid_t hostOwner = owner; 694 uint32_t group = p->getSyscallArg(tc, index); 695 gid_t hostGroup = group; 696 697 // Adjust path for cwd and redirection 698 path = p->checkPathRedirect(path); 699 700 int result = chown(path.c_str(), hostOwner, hostGroup); 701 return (result == -1) ? -errno : result; 702} 703 704SyscallReturn 705fchownFunc(SyscallDesc *desc, int num, ThreadContext *tc) 706{ 707 int index = 0; 708 auto p = tc->getProcessPtr(); 709 int tgt_fd = p->getSyscallArg(tc, index); 710 711 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 712 if (!ffdp) 713 return -EBADF; 714 int sim_fd = ffdp->getSimFD(); 715 716 /* XXX endianess */ 717 uint32_t owner = p->getSyscallArg(tc, index); 718 uid_t hostOwner = owner; 719 uint32_t group = p->getSyscallArg(tc, index); 720 gid_t hostGroup = group; 721 722 int result = fchown(sim_fd, hostOwner, hostGroup); 723 return (result == -1) ? -errno : result; 724} 725 726/** 727 * FIXME: The file description is not shared among file descriptors created 728 * with dup. Really, it's difficult to maintain fields like file offset or 729 * flags since an update to such a field won't be reflected in the metadata 730 * for the fd entries that we maintain for checkpoint restoration. 731 */ 732SyscallReturn 733dupFunc(SyscallDesc *desc, int num, ThreadContext *tc) 734{ 735 int index = 0; 736 auto p = tc->getProcessPtr(); 737 int tgt_fd = p->getSyscallArg(tc, index); 738 739 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 740 if (!old_hbfdp) 741 return -EBADF; 742 int sim_fd = old_hbfdp->getSimFD(); 743 744 int result = dup(sim_fd); 745 if (result == -1) 746 return -errno; 747 748 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone()); 749 new_hbfdp->setSimFD(result); 750 new_hbfdp->setCOE(false); 751 return p->fds->allocFD(new_hbfdp); 752} 753 754SyscallReturn 755dup2Func(SyscallDesc *desc, int num, ThreadContext *tc) 756{ 757 int index = 0; 758 auto p = tc->getProcessPtr(); 759 int old_tgt_fd = p->getSyscallArg(tc, index); 760 auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]); 761 if (!old_hbp) 762 return -EBADF; 763 int old_sim_fd = old_hbp->getSimFD(); 764 765 /** 766 * We need a valid host file descriptor number to be able to pass into 767 * the second parameter for dup2 (newfd), but we don't know what the 768 * viable numbers are; we execute the open call to retrieve one. 769 */ 770 int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY)); 771 if (res_fd == -1) 772 return -errno; 773 774 int new_tgt_fd = p->getSyscallArg(tc, index); 775 auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]); 776 if (new_hbp) 777 p->fds->closeFDEntry(new_tgt_fd); 778 new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone()); 779 new_hbp->setSimFD(res_fd); 780 new_hbp->setCOE(false); 781 782 return p->fds->allocFD(new_hbp); 783} 784 785SyscallReturn 786fcntlFunc(SyscallDesc *desc, int num, ThreadContext *tc) 787{ 788 int arg; 789 int index = 0; 790 auto p = tc->getProcessPtr(); 791 int tgt_fd = p->getSyscallArg(tc, index); 792 int cmd = p->getSyscallArg(tc, index); 793 794 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 795 if (!hbfdp) 796 return -EBADF; 797 int sim_fd = hbfdp->getSimFD(); 798 799 int coe = hbfdp->getCOE(); 800 801 switch (cmd) { 802 case F_GETFD: 803 return coe & FD_CLOEXEC; 804 805 case F_SETFD: { 806 arg = p->getSyscallArg(tc, index); 807 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 808 return 0; 809 } 810 811 // Rely on the host to maintain the file status flags for this file 812 // description rather than maintain it ourselves. Admittedly, this 813 // is suboptimal (and possibly error prone), but it is difficult to 814 // maintain the flags by tracking them across the different descriptors 815 // (that refer to this file description) caused by clone, dup, and 816 // subsequent fcntls. 817 case F_GETFL: 818 case F_SETFL: { 819 arg = p->getSyscallArg(tc, index); 820 int rv = fcntl(sim_fd, cmd, arg); 821 return (rv == -1) ? -errno : rv; 822 } 823 824 default: 825 warn("fcntl: unsupported command %d\n", cmd); 826 return 0; 827 } 828} 829 830SyscallReturn 831fcntl64Func(SyscallDesc *desc, int num, ThreadContext *tc) 832{ 833 int index = 0; 834 auto p = tc->getProcessPtr(); 835 int tgt_fd = p->getSyscallArg(tc, index); 836 837 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 838 if (!hbfdp) 839 return -EBADF; 840 int sim_fd = hbfdp->getSimFD(); 841 842 int cmd = p->getSyscallArg(tc, index); 843 switch (cmd) { 844 case 33: //F_GETLK64 845 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 846 return -EMFILE; 847 848 case 34: // F_SETLK64 849 case 35: // F_SETLKW64 850 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 851 tgt_fd); 852 return -EMFILE; 853 854 default: 855 // not sure if this is totally valid, but we'll pass it through 856 // to the underlying OS 857 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 858 return fcntl(sim_fd, cmd); 859 } 860} 861 862SyscallReturn 863pipeImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool pseudoPipe) 864{ 865 int sim_fds[2], tgt_fds[2]; 866 auto p = tc->getProcessPtr(); 867 868 int pipe_retval = pipe(sim_fds); 869 if (pipe_retval == -1) 870 return -errno; 871 872 auto rend = PipeFDEntry::EndType::read; 873 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 874 tgt_fds[0] = p->fds->allocFD(rpfd); 875 876 auto wend = PipeFDEntry::EndType::write; 877 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 878 tgt_fds[1] = p->fds->allocFD(wpfd); 879 880 /** 881 * Now patch the read object to record the target file descriptor chosen 882 * as the write end of the pipe. 883 */ 884 rpfd->setPipeReadSource(tgt_fds[1]); 885 886 /** 887 * Alpha Linux convention for pipe() is that fd[0] is returned as 888 * the return value of the function, and fd[1] is returned in r20. 889 */ 890 if (pseudoPipe) { 891 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 892 return tgt_fds[0]; 893 } 894 895 int index = 0; 896 Addr tgt_addr = p->getSyscallArg(tc, index); 897 898 /** 899 * Copy the target file descriptors into buffer space and then copy 900 * the buffer space back into the target address space. 901 */ 902 BufferArg tgt_handle(tgt_addr, sizeof(int[2])); 903 int *buf_ptr = (int*)tgt_handle.bufferPtr(); 904 buf_ptr[0] = tgt_fds[0]; 905 buf_ptr[1] = tgt_fds[1]; 906 tgt_handle.copyOut(tc->getMemProxy()); 907 return 0; 908} 909 910SyscallReturn 911pipePseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 912{ 913 return pipeImpl(desc, callnum, tc, true); 914} 915 916SyscallReturn 917pipeFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 918{ 919 return pipeImpl(desc, callnum, tc, false); 920} 921 922SyscallReturn 923setpgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 924{ 925 int index = 0; 926 auto process = tc->getProcessPtr(); 927 int pid = process->getSyscallArg(tc, index); 928 int pgid = process->getSyscallArg(tc, index); 929 930 if (pgid < 0) 931 return -EINVAL; 932 933 if (pid == 0) { 934 process->setpgid(process->pid()); 935 return 0; 936 } 937 938 Process *matched_ph = nullptr; 939 System *sysh = tc->getSystemPtr(); 940 941 // Retrieves process pointer from active/suspended thread contexts. 942 for (int i = 0; i < sysh->numContexts(); i++) { 943 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 944 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 945 Process *walk_ph = (Process*)temp_h; 946 947 if (walk_ph && walk_ph->pid() == process->pid()) 948 matched_ph = walk_ph; 949 } 950 } 951 952 assert(matched_ph); 953 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 954 955 return 0; 956} 957 958SyscallReturn 959getpidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 960{ 961 // Make up a PID. There's no interprocess communication in 962 // fake_syscall mode, so there's no way for a process to know it's 963 // not getting a unique value. 964 965 auto process = tc->getProcessPtr(); 966 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 967 return process->pid(); 968} 969 970 971SyscallReturn 972getuidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 973{ 974 // Make up a UID and EUID... it shouldn't matter, and we want the 975 // simulation to be deterministic. 976 977 // EUID goes in r20. 978 auto process = tc->getProcessPtr(); 979 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 980 return process->uid(); // UID 981} 982 983 984SyscallReturn 985getgidPseudoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 986{ 987 // Get current group ID. EGID goes in r20. 988 auto process = tc->getProcessPtr(); 989 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 990 return process->gid(); 991} 992 993 994SyscallReturn 995setuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 996{ 997 // can't fathom why a benchmark would call this. 998 int index = 0; 999 auto process = tc->getProcessPtr(); 1000 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 1001 return 0; 1002} 1003 1004SyscallReturn 1005getpidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1006{ 1007 auto process = tc->getProcessPtr(); 1008 return process->tgid(); 1009} 1010 1011SyscallReturn 1012gettidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1013{ 1014 auto process = tc->getProcessPtr(); 1015 return process->pid(); 1016} 1017 1018SyscallReturn 1019getppidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1020{ 1021 auto process = tc->getProcessPtr(); 1022 return process->ppid(); 1023} 1024 1025SyscallReturn 1026getuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1027{ 1028 auto process = tc->getProcessPtr(); 1029 return process->uid(); // UID 1030} 1031 1032SyscallReturn 1033geteuidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1034{ 1035 auto process = tc->getProcessPtr(); 1036 return process->euid(); // UID 1037} 1038 1039SyscallReturn 1040getgidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1041{ 1042 auto process = tc->getProcessPtr(); 1043 return process->gid(); 1044} 1045 1046SyscallReturn 1047getegidFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1048{ 1049 auto process = tc->getProcessPtr(); 1050 return process->egid(); 1051} 1052 1053SyscallReturn 1054fallocateFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1055{ 1056#if defined(__linux__) 1057 int index = 0; 1058 auto p = tc->getProcessPtr(); 1059 int tgt_fd = p->getSyscallArg(tc, index); 1060 int mode = p->getSyscallArg(tc, index); 1061 off_t offset = p->getSyscallArg(tc, index); 1062 off_t len = p->getSyscallArg(tc, index); 1063 1064 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1065 if (!ffdp) 1066 return -EBADF; 1067 int sim_fd = ffdp->getSimFD(); 1068 1069 int result = fallocate(sim_fd, mode, offset, len); 1070 if (result < 0) 1071 return -errno; 1072 return 0; 1073#else 1074 warnUnsupportedOS("fallocate"); 1075 return -1; 1076#endif 1077} 1078 1079SyscallReturn 1080accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, int index) 1081{ 1082 string path; 1083 auto p = tc->getProcessPtr(); 1084 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1085 return -EFAULT; 1086 1087 // Adjust path for cwd and redirection 1088 path = p->checkPathRedirect(path); 1089 1090 mode_t mode = p->getSyscallArg(tc, index); 1091 1092 int result = access(path.c_str(), mode); 1093 return (result == -1) ? -errno : result; 1094} 1095 1096SyscallReturn 1097accessFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1098{ 1099 return accessFunc(desc, callnum, tc, 0); 1100} 1101 1102SyscallReturn 1103mknodFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1104{ 1105 auto p = tc->getProcessPtr(); 1106 int index = 0; 1107 std::string path; 1108 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1109 return -EFAULT; 1110 1111 path = p->checkPathRedirect(path); 1112 mode_t mode = p->getSyscallArg(tc, index); 1113 dev_t dev = p->getSyscallArg(tc, index); 1114 1115 auto result = mknod(path.c_str(), mode, dev); 1116 return (result == -1) ? -errno : result; 1117} 1118 1119SyscallReturn 1120chdirFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1121{ 1122 auto p = tc->getProcessPtr(); 1123 int index = 0; 1124 std::string path; 1125 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1126 return -EFAULT; 1127 1128 std::string tgt_cwd; 1129 if (startswith(path, "/")) { 1130 tgt_cwd = path; 1131 } else { 1132 char buf[PATH_MAX]; 1133 tgt_cwd = realpath((p->tgtCwd + "/" + path).c_str(), buf); 1134 } 1135 std::string host_cwd = p->checkPathRedirect(tgt_cwd); 1136 1137 int result = chdir(host_cwd.c_str()); 1138 1139 if (result == -1) 1140 return -errno; 1141 1142 p->hostCwd = host_cwd; 1143 p->tgtCwd = tgt_cwd; 1144 return result; 1145} 1146 1147SyscallReturn 1148rmdirFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1149{ 1150 auto p = tc->getProcessPtr(); 1151 int index = 0; 1152 std::string path; 1153 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1154 return -EFAULT; 1155 1156 path = p->checkPathRedirect(path); 1157 1158 auto result = rmdir(path.c_str()); 1159 return (result == -1) ? -errno : result; 1160} 1161 1162#if defined(SYS_getdents) || defined(SYS_getdents64) 1163template<typename DE, int SYS_NUM> 1164static SyscallReturn 1165getdentsImpl(SyscallDesc *desc, int callnum, ThreadContext *tc) 1166{ 1167 int index = 0; 1168 auto p = tc->getProcessPtr(); 1169 int tgt_fd = p->getSyscallArg(tc, index); 1170 Addr buf_ptr = p->getSyscallArg(tc, index); 1171 unsigned count = p->getSyscallArg(tc, index); 1172 1173 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1174 if (!hbfdp) 1175 return -EBADF; 1176 int sim_fd = hbfdp->getSimFD(); 1177 1178 BufferArg buf_arg(buf_ptr, count); 1179 auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count); 1180 1181 if (status == -1) 1182 return -errno; 1183 1184 unsigned traversed = 0; 1185 while (traversed < status) { 1186 DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed); 1187 1188 auto host_reclen = buffer->d_reclen; 1189 1190 /** 1191 * Convert the byte ordering from the host to the target before 1192 * passing the data back into the target's address space to preserve 1193 * endianness. 1194 */ 1195 buffer->d_ino = htog(buffer->d_ino); 1196 buffer->d_off = htog(buffer->d_off); 1197 buffer->d_reclen = htog(buffer->d_reclen); 1198 1199 traversed += host_reclen; 1200 } 1201 1202 buf_arg.copyOut(tc->getMemProxy()); 1203 return status; 1204} 1205#endif 1206 1207#if defined(SYS_getdents) 1208SyscallReturn 1209getdentsFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1210{ 1211 typedef struct linux_dirent { 1212 unsigned long d_ino; 1213 unsigned long d_off; 1214 unsigned short d_reclen; 1215 char dname[]; 1216 } LinDent; 1217 1218 return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, tc); 1219} 1220#endif 1221 1222#if defined(SYS_getdents64) 1223SyscallReturn 1224getdents64Func(SyscallDesc *desc, int callnum, ThreadContext *tc) 1225{ 1226 typedef struct linux_dirent64 { 1227 ino64_t d_ino; 1228 off64_t d_off; 1229 unsigned short d_reclen; 1230 char dname[]; 1231 } LinDent64; 1232 1233 return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, tc); 1234} 1235#endif 1236 1237SyscallReturn 1238shutdownFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1239{ 1240 int index = 0; 1241 auto p = tc->getProcessPtr(); 1242 int tgt_fd = p->getSyscallArg(tc, index); 1243 int how = p->getSyscallArg(tc, index); 1244 1245 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1246 if (!sfdp) 1247 return -EBADF; 1248 int sim_fd = sfdp->getSimFD(); 1249 1250 int retval = shutdown(sim_fd, how); 1251 1252 return (retval == -1) ? -errno : retval; 1253} 1254 1255SyscallReturn 1256bindFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1257{ 1258 int index = 0; 1259 auto p = tc->getProcessPtr(); 1260 int tgt_fd = p->getSyscallArg(tc, index); 1261 Addr buf_ptr = p->getSyscallArg(tc, index); 1262 int addrlen = p->getSyscallArg(tc, index); 1263 1264 BufferArg bufSock(buf_ptr, addrlen); 1265 bufSock.copyIn(tc->getMemProxy()); 1266 1267 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1268 if (!sfdp) 1269 return -EBADF; 1270 int sim_fd = sfdp->getSimFD(); 1271 1272 int status = ::bind(sim_fd, 1273 (struct sockaddr *)bufSock.bufferPtr(), 1274 addrlen); 1275 1276 return (status == -1) ? -errno : status; 1277} 1278 1279SyscallReturn 1280listenFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1281{ 1282 int index = 0; 1283 auto p = tc->getProcessPtr(); 1284 int tgt_fd = p->getSyscallArg(tc, index); 1285 int backlog = p->getSyscallArg(tc, index); 1286 1287 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1288 if (!sfdp) 1289 return -EBADF; 1290 int sim_fd = sfdp->getSimFD(); 1291 1292 int status = listen(sim_fd, backlog); 1293 1294 return (status == -1) ? -errno : status; 1295} 1296 1297SyscallReturn 1298connectFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1299{ 1300 int index = 0; 1301 auto p = tc->getProcessPtr(); 1302 int tgt_fd = p->getSyscallArg(tc, index); 1303 Addr buf_ptr = p->getSyscallArg(tc, index); 1304 int addrlen = p->getSyscallArg(tc, index); 1305 1306 BufferArg addr(buf_ptr, addrlen); 1307 addr.copyIn(tc->getMemProxy()); 1308 1309 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1310 if (!sfdp) 1311 return -EBADF; 1312 int sim_fd = sfdp->getSimFD(); 1313 1314 int status = connect(sim_fd, 1315 (struct sockaddr *)addr.bufferPtr(), 1316 (socklen_t)addrlen); 1317 1318 return (status == -1) ? -errno : status; 1319} 1320 1321SyscallReturn 1322recvfromFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1323{ 1324 int index = 0; 1325 auto p = tc->getProcessPtr(); 1326 int tgt_fd = p->getSyscallArg(tc, index); 1327 Addr bufrPtr = p->getSyscallArg(tc, index); 1328 size_t bufrLen = p->getSyscallArg(tc, index); 1329 int flags = p->getSyscallArg(tc, index); 1330 Addr addrPtr = p->getSyscallArg(tc, index); 1331 Addr addrlenPtr = p->getSyscallArg(tc, index); 1332 1333 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1334 if (!sfdp) 1335 return -EBADF; 1336 int sim_fd = sfdp->getSimFD(); 1337 1338 // Reserve buffer space. 1339 BufferArg bufrBuf(bufrPtr, bufrLen); 1340 1341 // Get address length. 1342 socklen_t addrLen = 0; 1343 if (addrlenPtr != 0) { 1344 // Read address length parameter. 1345 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1346 addrlenBuf.copyIn(tc->getMemProxy()); 1347 addrLen = *((socklen_t *)addrlenBuf.bufferPtr()); 1348 } 1349 1350 struct sockaddr sa, *sap = NULL; 1351 if (addrLen != 0) { 1352 BufferArg addrBuf(addrPtr, addrLen); 1353 addrBuf.copyIn(tc->getMemProxy()); 1354 memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(), 1355 sizeof(struct sockaddr)); 1356 sap = &sa; 1357 } 1358 1359 ssize_t recvd_size = recvfrom(sim_fd, 1360 (void *)bufrBuf.bufferPtr(), 1361 bufrLen, flags, sap, (socklen_t *)&addrLen); 1362 1363 if (recvd_size == -1) 1364 return -errno; 1365 1366 // Pass the received data out. 1367 bufrBuf.copyOut(tc->getMemProxy()); 1368 1369 // Copy address to addrPtr and pass it on. 1370 if (sap != NULL) { 1371 BufferArg addrBuf(addrPtr, addrLen); 1372 memcpy(addrBuf.bufferPtr(), sap, sizeof(sa)); 1373 addrBuf.copyOut(tc->getMemProxy()); 1374 } 1375 1376 // Copy len to addrlenPtr and pass it on. 1377 if (addrLen != 0) { 1378 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1379 *(socklen_t *)addrlenBuf.bufferPtr() = addrLen; 1380 addrlenBuf.copyOut(tc->getMemProxy()); 1381 } 1382 1383 return recvd_size; 1384} 1385 1386SyscallReturn 1387sendtoFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1388{ 1389 int index = 0; 1390 auto p = tc->getProcessPtr(); 1391 int tgt_fd = p->getSyscallArg(tc, index); 1392 Addr bufrPtr = p->getSyscallArg(tc, index); 1393 size_t bufrLen = p->getSyscallArg(tc, index); 1394 int flags = p->getSyscallArg(tc, index); 1395 Addr addrPtr = p->getSyscallArg(tc, index); 1396 socklen_t addrLen = p->getSyscallArg(tc, index); 1397 1398 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1399 if (!sfdp) 1400 return -EBADF; 1401 int sim_fd = sfdp->getSimFD(); 1402 1403 // Reserve buffer space. 1404 BufferArg bufrBuf(bufrPtr, bufrLen); 1405 bufrBuf.copyIn(tc->getMemProxy()); 1406 1407 struct sockaddr sa, *sap = nullptr; 1408 memset(&sa, 0, sizeof(sockaddr)); 1409 if (addrLen != 0) { 1410 BufferArg addrBuf(addrPtr, addrLen); 1411 addrBuf.copyIn(tc->getMemProxy()); 1412 memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen); 1413 sap = &sa; 1414 } 1415 1416 ssize_t sent_size = sendto(sim_fd, 1417 (void *)bufrBuf.bufferPtr(), 1418 bufrLen, flags, sap, (socklen_t)addrLen); 1419 1420 return (sent_size == -1) ? -errno : sent_size; 1421} 1422 1423SyscallReturn 1424recvmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1425{ 1426 int index = 0; 1427 auto p = tc->getProcessPtr(); 1428 int tgt_fd = p->getSyscallArg(tc, index); 1429 Addr msgPtr = p->getSyscallArg(tc, index); 1430 int flags = p->getSyscallArg(tc, index); 1431 1432 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1433 if (!sfdp) 1434 return -EBADF; 1435 int sim_fd = sfdp->getSimFD(); 1436 1437 /** 1438 * struct msghdr { 1439 * void *msg_name; // optional address 1440 * socklen_t msg_namelen; // size of address 1441 * struct iovec *msg_iov; // iovec array 1442 * size_t msg_iovlen; // number entries in msg_iov 1443 * i // entries correspond to buffer 1444 * void *msg_control; // ancillary data 1445 * size_t msg_controllen; // ancillary data buffer len 1446 * int msg_flags; // flags on received message 1447 * }; 1448 * 1449 * struct iovec { 1450 * void *iov_base; // starting address 1451 * size_t iov_len; // number of bytes to transfer 1452 * }; 1453 */ 1454 1455 /** 1456 * The plan with this system call is to replace all of the pointers in the 1457 * structure and the substructure with BufferArg class pointers. We will 1458 * copy every field from the structures into our BufferArg classes. 1459 */ 1460 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1461 msgBuf.copyIn(tc->getMemProxy()); 1462 struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr(); 1463 1464 /** 1465 * We will use these address place holders to retain the pointers which 1466 * we are going to replace with our own buffers in our simulator address 1467 * space. 1468 */ 1469 Addr msg_name_phold = 0; 1470 Addr msg_iov_phold = 0; 1471 Addr iovec_base_phold[msgHdr->msg_iovlen]; 1472 Addr msg_control_phold = 0; 1473 1474 /** 1475 * Record msg_name pointer then replace with buffer pointer. 1476 */ 1477 BufferArg *nameBuf = NULL; 1478 if (msgHdr->msg_name) { 1479 /*1*/msg_name_phold = (Addr)msgHdr->msg_name; 1480 /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen); 1481 /*3*/nameBuf->copyIn(tc->getMemProxy()); 1482 /*4*/msgHdr->msg_name = nameBuf->bufferPtr(); 1483 } 1484 1485 /** 1486 * Record msg_iov pointer then replace with buffer pointer. Also, setup 1487 * an array of buffer pointers for the iovec structs record and replace 1488 * their pointers with buffer pointers. 1489 */ 1490 BufferArg *iovBuf = NULL; 1491 BufferArg *iovecBuf[msgHdr->msg_iovlen]; 1492 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1493 iovec_base_phold[i] = 0; 1494 iovecBuf[i] = NULL; 1495 } 1496 1497 if (msgHdr->msg_iov) { 1498 /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov; 1499 /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen * 1500 sizeof(struct iovec)); 1501 /*3*/iovBuf->copyIn(tc->getMemProxy()); 1502 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1503 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1504 /*1*/iovec_base_phold[i] = 1505 (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base; 1506 /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i], 1507 ((struct iovec *)iovBuf->bufferPtr())[i].iov_len); 1508 /*3*/iovecBuf[i]->copyIn(tc->getMemProxy()); 1509 /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1510 iovecBuf[i]->bufferPtr(); 1511 } 1512 } 1513 /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr(); 1514 } 1515 1516 /** 1517 * Record msg_control pointer then replace with buffer pointer. 1518 */ 1519 BufferArg *controlBuf = NULL; 1520 if (msgHdr->msg_control) { 1521 /*1*/msg_control_phold = (Addr)msgHdr->msg_control; 1522 /*2*/controlBuf = new BufferArg(msg_control_phold, 1523 CMSG_ALIGN(msgHdr->msg_controllen)); 1524 /*3*/controlBuf->copyIn(tc->getMemProxy()); 1525 /*4*/msgHdr->msg_control = controlBuf->bufferPtr(); 1526 } 1527 1528 ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags); 1529 1530 if (recvd_size < 0) 1531 return -errno; 1532 1533 if (msgHdr->msg_name) { 1534 nameBuf->copyOut(tc->getMemProxy()); 1535 delete(nameBuf); 1536 msgHdr->msg_name = (void *)msg_name_phold; 1537 } 1538 1539 if (msgHdr->msg_iov) { 1540 for (int i = 0; i< msgHdr->msg_iovlen; i++) { 1541 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1542 iovecBuf[i]->copyOut(tc->getMemProxy()); 1543 delete iovecBuf[i]; 1544 ((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1545 (void *)iovec_base_phold[i]; 1546 } 1547 } 1548 iovBuf->copyOut(tc->getMemProxy()); 1549 delete iovBuf; 1550 msgHdr->msg_iov = (struct iovec *)msg_iov_phold; 1551 } 1552 1553 if (msgHdr->msg_control) { 1554 controlBuf->copyOut(tc->getMemProxy()); 1555 delete(controlBuf); 1556 msgHdr->msg_control = (void *)msg_control_phold; 1557 } 1558 1559 msgBuf.copyOut(tc->getMemProxy()); 1560 1561 return recvd_size; 1562} 1563 1564SyscallReturn 1565sendmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1566{ 1567 int index = 0; 1568 auto p = tc->getProcessPtr(); 1569 int tgt_fd = p->getSyscallArg(tc, index); 1570 Addr msgPtr = p->getSyscallArg(tc, index); 1571 int flags = p->getSyscallArg(tc, index); 1572 1573 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1574 if (!sfdp) 1575 return -EBADF; 1576 int sim_fd = sfdp->getSimFD(); 1577 1578 /** 1579 * Reserve buffer space. 1580 */ 1581 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1582 msgBuf.copyIn(tc->getMemProxy()); 1583 struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr()); 1584 1585 /** 1586 * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling 1587 * recvmsg without a buffer. 1588 */ 1589 struct iovec *iovPtr = msgHdr.msg_iov; 1590 BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen); 1591 iovBuf.copyIn(tc->getMemProxy()); 1592 struct iovec *iov = (struct iovec *)iovBuf.bufferPtr(); 1593 msgHdr.msg_iov = iov; 1594 1595 /** 1596 * Cannot instantiate buffers till inside the loop. 1597 * Create array to hold buffer addresses, to be used during copyIn of 1598 * send data. 1599 */ 1600 BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen 1601 * sizeof(BufferArg *)); 1602 1603 /** 1604 * Iterate through the iovec structures: 1605 * Get the base buffer addreses, reserve iov_len amount of space for each. 1606 * Put the buf address into the bufferArray for later retrieval. 1607 */ 1608 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1609 Addr basePtr = (Addr) iov[iovIndex].iov_base; 1610 bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len); 1611 bufferArray[iovIndex]->copyIn(tc->getMemProxy()); 1612 iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr(); 1613 } 1614 1615 ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags); 1616 int local_errno = errno; 1617 1618 /** 1619 * Free dynamically allocated memory. 1620 */ 1621 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1622 BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex]; 1623 delete(baseBuf); 1624 } 1625 1626 /** 1627 * Malloced above. 1628 */ 1629 free(bufferArray); 1630 1631 return (sent_size < 0) ? -local_errno : sent_size; 1632} 1633 1634SyscallReturn 1635getsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1636{ 1637 // union of all possible return value types from getsockopt 1638 union val { 1639 int i_val; 1640 long l_val; 1641 struct linger linger_val; 1642 struct timeval timeval_val; 1643 } val; 1644 1645 int index = 0; 1646 auto p = tc->getProcessPtr(); 1647 int tgt_fd = p->getSyscallArg(tc, index); 1648 int level = p->getSyscallArg(tc, index); 1649 int optname = p->getSyscallArg(tc, index); 1650 Addr valPtr = p->getSyscallArg(tc, index); 1651 Addr lenPtr = p->getSyscallArg(tc, index); 1652 1653 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1654 if (!sfdp) 1655 return -EBADF; 1656 int sim_fd = sfdp->getSimFD(); 1657 1658 socklen_t len = sizeof(val); 1659 int status = getsockopt(sim_fd, level, optname, &val, &len); 1660 1661 if (status == -1) 1662 return -errno; 1663 1664 // copy val to valPtr and pass it on 1665 BufferArg valBuf(valPtr, sizeof(val)); 1666 memcpy(valBuf.bufferPtr(), &val, sizeof(val)); 1667 valBuf.copyOut(tc->getMemProxy()); 1668 1669 // copy len to lenPtr and pass it on 1670 BufferArg lenBuf(lenPtr, sizeof(len)); 1671 memcpy(lenBuf.bufferPtr(), &len, sizeof(len)); 1672 lenBuf.copyOut(tc->getMemProxy()); 1673 1674 return status; 1675} 1676 1677SyscallReturn 1678getsocknameFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1679{ 1680 int index = 0; 1681 auto p = tc->getProcessPtr(); 1682 int tgt_fd = p->getSyscallArg(tc, index); 1683 Addr addrPtr = p->getSyscallArg(tc, index); 1684 Addr lenPtr = p->getSyscallArg(tc, index); 1685 1686 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1687 if (!sfdp) 1688 return -EBADF; 1689 int sim_fd = sfdp->getSimFD(); 1690 1691 // lenPtr is an in-out paramenter: 1692 // sending the address length in, conveying the final length out 1693 1694 // Read in the value of len from the passed pointer. 1695 BufferArg lenBuf(lenPtr, sizeof(socklen_t)); 1696 lenBuf.copyIn(tc->getMemProxy()); 1697 socklen_t len = *(socklen_t *)lenBuf.bufferPtr(); 1698 1699 struct sockaddr sa; 1700 int status = getsockname(sim_fd, &sa, &len); 1701 1702 if (status == -1) 1703 return -errno; 1704 1705 // Copy address to addrPtr and pass it on. 1706 BufferArg addrBuf(addrPtr, sizeof(sa)); 1707 memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa)); 1708 addrBuf.copyOut(tc->getMemProxy()); 1709 1710 // Copy len to lenPtr and pass it on. 1711 *(socklen_t *)lenBuf.bufferPtr() = len; 1712 lenBuf.copyOut(tc->getMemProxy()); 1713 1714 return status; 1715} 1716 1717SyscallReturn 1718getpeernameFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1719{ 1720 int index = 0; 1721 auto p = tc->getProcessPtr(); 1722 int tgt_fd = p->getSyscallArg(tc, index); 1723 Addr sockAddrPtr = p->getSyscallArg(tc, index); 1724 Addr addrlenPtr = p->getSyscallArg(tc, index); 1725 1726 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1727 if (!sfdp) 1728 return -EBADF; 1729 int sim_fd = sfdp->getSimFD(); 1730 1731 BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned)); 1732 bufAddrlen.copyIn(tc->getMemProxy()); 1733 BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr()); 1734 1735 int retval = getpeername(sim_fd, 1736 (struct sockaddr *)bufSock.bufferPtr(), 1737 (unsigned *)bufAddrlen.bufferPtr()); 1738 1739 if (retval != -1) { 1740 bufSock.copyOut(tc->getMemProxy()); 1741 bufAddrlen.copyOut(tc->getMemProxy()); 1742 } 1743 1744 return (retval == -1) ? -errno : retval; 1745} 1746 1747SyscallReturn 1748setsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1749{ 1750 int index = 0; 1751 auto p = tc->getProcessPtr(); 1752 int tgt_fd = p->getSyscallArg(tc, index); 1753 int level = p->getSyscallArg(tc, index); 1754 int optname = p->getSyscallArg(tc, index); 1755 Addr valPtr = p->getSyscallArg(tc, index); 1756 socklen_t len = p->getSyscallArg(tc, index); 1757 1758 BufferArg valBuf(valPtr, len); 1759 valBuf.copyIn(tc->getMemProxy()); 1760 1761 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1762 if (!sfdp) 1763 return -EBADF; 1764 int sim_fd = sfdp->getSimFD(); 1765 1766 int status = setsockopt(sim_fd, level, optname, 1767 (struct sockaddr *)valBuf.bufferPtr(), len); 1768 1769 return (status == -1) ? -errno : status; 1770} 1771 1772