diff options
Diffstat (limited to 'sim')
-rw-r--r-- | sim/process.cc (renamed from sim/prog.cc) | 72 | ||||
-rw-r--r-- | sim/process.hh (renamed from sim/prog.hh) | 26 | ||||
-rw-r--r-- | sim/syscall_emul.cc | 197 | ||||
-rw-r--r-- | sim/syscall_emul.hh | 465 |
4 files changed, 733 insertions, 27 deletions
diff --git a/sim/prog.cc b/sim/process.cc index fca4b4505..bb4333896 100644 --- a/sim/prog.cc +++ b/sim/process.cc @@ -42,9 +42,14 @@ #include "mem/functional_mem/main_memory.hh" #include "sim/builder.hh" #include "sim/fake_syscall.hh" -#include "sim/prog.hh" +#include "sim/process.hh" #include "sim/sim_stats.hh" +#ifdef TARGET_ALPHA +#include "arch/alpha/alpha_tru64_process.hh" +#include "arch/alpha/alpha_linux_process.hh" +#endif + using namespace std; // @@ -53,13 +58,9 @@ using namespace std; // mode when we do have an OS // #ifdef FULL_SYSTEM -#error "prog.cc not compatible with FULL_SYSTEM" +#error "process.cc not compatible with FULL_SYSTEM" #endif -// max allowable number of processes: should be no real cost to -// cranking this up if necessary -const int MAX_PROCESSES = 8; - // current number of allocated processes int num_processes = 0; @@ -242,16 +243,12 @@ copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, memory->access(Write, array_ptr, &data_ptr, sizeof(Addr)); } -LiveProcess::LiveProcess(const string &name, +LiveProcess::LiveProcess(const string &name, ObjectFile *objFile, int stdin_fd, int stdout_fd, int stderr_fd, vector<string> &argv, vector<string> &envp) : Process(name, stdin_fd, stdout_fd, stderr_fd) { prog_fname = argv[0]; - ObjectFile *objFile = createObjectFile(prog_fname); - if (objFile == NULL) { - fatal("Can't load object file %s", prog_fname); - } prog_entry = objFile->entryPoint(); text_base = objFile->textBase(); @@ -267,6 +264,10 @@ LiveProcess::LiveProcess(const string &name, // code should get moved to some architecture-specific spot. stack_base = text_base - (409600+4096); + // Set up region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_base = 0x10000; + // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); @@ -316,12 +317,45 @@ LiveProcess::LiveProcess(const string &name, } -void -LiveProcess::syscall(ExecContext *xc) +LiveProcess * +LiveProcess::create(const string &name, + int stdin_fd, int stdout_fd, int stderr_fd, + vector<string> &argv, vector<string> &envp) { - num_syscalls++; + LiveProcess *process = NULL; + ObjectFile *objFile = createObjectFile(argv[0]); + if (objFile == NULL) { + fatal("Can't load object file %s", argv[0]); + } + + // check object type & set up syscall emulation pointer + if (objFile->getArch() == ObjectFile::Alpha) { + switch (objFile->getOpSys()) { + case ObjectFile::Tru64: + process = new AlphaTru64Process(name, objFile, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + case ObjectFile::Linux: + process = new AlphaLinuxProcess(name, objFile, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + default: + fatal("Unknown/unsupported operating system."); + } + } else { + fatal("Unknown object file architecture."); + } + + delete objFile; + + if (process == NULL) + fatal("Unknown error creating process object."); - fake_syscall(this, xc); + return process; } @@ -357,10 +391,10 @@ CREATE_SIM_OBJECT(LiveProcess) // We do this with "temp" because of the bogus compiler warning // you get with g++ 2.95 -O if you just "return new LiveProcess(..." - LiveProcess *temp = new LiveProcess(getInstanceName(), - stdin_fd, stdout_fd, stderr_fd, - cmd, - env.isValid() ? env : null_vec); + LiveProcess *temp = LiveProcess::create(getInstanceName(), + stdin_fd, stdout_fd, stderr_fd, + cmd, + env.isValid() ? env : null_vec); return temp; } diff --git a/sim/prog.hh b/sim/process.hh index e93dd684c..5df5736ff 100644 --- a/sim/prog.hh +++ b/sim/process.hh @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __PROG_HH__ -#define __PROG_HH__ +#ifndef __PROCESS_HH__ +#define __PROCESS_HH__ // // The purpose of this code is to fake the loader & syscall mechanism @@ -89,10 +89,12 @@ class Process : public SimObject unsigned stack_size; // initial stack size Addr stack_min; // lowest address accessed on the stack - // addr to use for next stack region (for multithreaded apps) Addr next_thread_stack_base; + // Base of region for mmaps (when user doesn't specify an address). + Addr mmap_base; + std::string prog_fname; // file name Addr prog_entry; // entry point (initial PC) @@ -165,18 +167,26 @@ class Process : public SimObject // // "Live" process with system calls redirected to host system // -class MainMemory; +class ObjectFile; class LiveProcess : public Process { - public: - LiveProcess(const std::string &name, + protected: + LiveProcess(const std::string &name, ObjectFile *objFile, int stdin_fd, int stdout_fd, int stderr_fd, std::vector<std::string> &argv, std::vector<std::string> &envp); - virtual void syscall(ExecContext *xc); + public: + // this function is used to create the LiveProcess object, since + // we can't tell which subclass of LiveProcess to use until we + // open and look at the object file. + static LiveProcess *create(const std::string &name, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); }; + #endif // !FULL_SYSTEM -#endif // __PROG_HH__ +#endif // __PROCESS_HH__ diff --git a/sim/syscall_emul.cc b/sim/syscall_emul.cc new file mode 100644 index 000000000..0e4e78612 --- /dev/null +++ b/sim/syscall_emul.cc @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> + +#include <string> +#include <iostream> + +#include "sim/syscall_emul.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "cpu/base_cpu.hh" +#include "sim/process.hh" + +#include "sim/sim_events.hh" + +using namespace std; + +void +SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc) +{ + DPRINTFR(SyscallVerbose, "%s: syscall %s called\n", + xc->cpu->name(), name); + + int retval = (*funcPtr)(this, callnum, process, xc); + + DPRINTFR(SyscallVerbose, "%s: syscall %s returns %d\n", + xc->cpu->name(), name, retval); + + if (!((flags & SyscallDesc::SuppressReturnValue) && retval == 0)) + xc->setSyscallReturn(retval); +} + + +// +// Handler for unimplemented syscalls that we haven't thought about. +// +int +unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + cerr << "Error: syscall " << desc->name + << " (#" << callnum << ") unimplemented."; + cerr << " Args: " << xc->getSyscallArg(0) << ", " << xc->getSyscallArg(1) + << ", ..." << endl; + + abort(); +} + + +// +// Handler for unimplemented syscalls that we never intend to +// implement (signal handling, etc.) and should not affect the correct +// behavior of the program. Print a warning only if the appropriate +// trace flag is enabled. Return success to the target program. +// +int +ignoreFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + DCOUT(SyscallWarnings) << "Warning: ignoring syscall " << desc->name + << "(" << xc->getSyscallArg(0) + << ", " << xc->getSyscallArg(1) + << ", ...)" << endl; + + return 0; +} + + +int +exitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + new SimExitEvent("syscall caused exit", xc->getSyscallArg(0) & 0xff); + + return 1; +} + + +int +getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + return VMPageSize; +} + + +int +obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + // change brk addr to first arg + p->brk_point = xc->getSyscallArg(0); + return p->brk_point; +} + + +int +closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + return close(fd); +} + + +int +readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + int nbytes = xc->getSyscallArg(2); + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + + int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); + + if (bytes_read != -1) + bufArg.copyOut(xc->mem); + + return bytes_read; +} + +int +writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + int nbytes = xc->getSyscallArg(2); + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + + bufArg.copyIn(xc->mem); + + int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); + + fsync(fd); + + return bytes_written; +} + + +int +lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + uint64_t offs = xc->getSyscallArg(1); + int whence = xc->getSyscallArg(2); + + off_t result = lseek(fd, offs, whence); + + return (result == (off_t)-1) ? -errno : result; +} + + +int +munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + // given that we don't really implement mmap, munmap is really easy + return 0; +} + + +const char *hostname = "m5.eecs.umich.edu"; + +int +gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int name_len = xc->getSyscallArg(1); + BufferArg name(xc->getSyscallArg(0), name_len); + + strncpy((char *)name.bufferPtr(), hostname, name_len); + + name.copyOut(xc->mem); + + return 0; +} + + diff --git a/sim/syscall_emul.hh b/sim/syscall_emul.hh new file mode 100644 index 000000000..a02b4a608 --- /dev/null +++ b/sim/syscall_emul.hh @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYSCALL_EMUL_HH__ +#define __SYSCALL_EMUL_HH__ + +/// +/// @file syscall_emul.hh +/// +/// This file defines objects used to emulate syscalls from the target +/// application on the host machine. + +#include <string> + +#include "base/intmath.hh" // for RoundUp +#include "targetarch/isa_traits.hh" // for Addr +#include "mem/functional_mem/functional_memory.hh" + +class Process; +class ExecContext; + +/// +/// System call descriptor. +/// +class SyscallDesc { + + public: + + typedef int (*FuncPtr)(SyscallDesc *, int num, + Process *, ExecContext *); + + const char *name; //!< Syscall name (e.g., "open"). + FuncPtr funcPtr; //!< Pointer to emulation function. + int flags; //!< Flags (see Flags enum). + + + /// Flag values for controlling syscall behavior. + enum Flags { + /// Don't set return regs according to funcPtr return value. + /// Used for syscalls with non-standard return conventions + /// that explicitly set the ExecContext regs (e.g., + /// sigreturn). + SuppressReturnValue = 1 + }; + + /// Constructor. + SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) + : name(_name), funcPtr(_funcPtr), flags(_flags) + { + } + + /// Emulate the syscall. Public interface for calling through funcPtr. + void doSyscall(int callnum, Process *proc, ExecContext *xc); +}; + + +class BaseBufferArg { + + public: + + BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) + { + bufPtr = new uint8_t[size]; + // clear out buffer: in case we only partially populate this, + // and then do a copyOut(), we want to make sure we don't + // introduce any random junk into the simulated address space + memset(bufPtr, 0, size); + } + + virtual ~BaseBufferArg() { delete [] bufPtr; } + + // + // copy data into simulator space (read from target memory) + // + virtual bool copyIn(FunctionalMemory *mem) + { + mem->access(Read, addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + // + // copy data out of simulator space (write to target memory) + // + virtual bool copyOut(FunctionalMemory *mem) + { + mem->access(Write, addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + protected: + Addr addr; + int size; + uint8_t *bufPtr; +}; + + +class BufferArg : public BaseBufferArg +{ + public: + BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } + void *bufferPtr() { return bufPtr; } +}; + +template <class T> +class TypedBufferArg : public BaseBufferArg +{ + public: + // user can optionally specify a specific number of bytes to + // allocate to deal with those structs that have variable-size + // arrays at the end + TypedBufferArg(Addr _addr, int _size = sizeof(T)) + : BaseBufferArg(_addr, _size) + { } + + // type case + operator T*() { return (T *)bufPtr; } + + // dereference operators + T& operator*() { return *((T *)bufPtr); } + T* operator->() { return (T *)bufPtr; } + T& operator[](int i) { return ((T *)bufPtr)[i]; } +}; + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic enough that they +// don't need to be recompiled for different emulated OS's. They are +// defined in sim/syscall_emul.cc. +// +////////////////////////////////////////////////////////////////////// + + +int unimplementedFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int ignoreFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); + +int exitFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); +int gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc); + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic, but need to be +// templated to account for differences in types, constants, etc. +// +////////////////////////////////////////////////////////////////////// + +template <class OS> +int +ioctlFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + unsigned req = xc->getSyscallArg(1); + + // DPRINTFR(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); + + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + switch (req) { + case OS::TIOCISATTY: + case OS::TIOCGETP: + case OS::TIOCSETP: + case OS::TIOCSETN: + case OS::TIOCSETC: + case OS::TIOCGETC: + return -ENOTTY; + + default: + fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...)\n", fd, req); + } +} + +struct OpenFlagTransTable { + int tgtFlag; + int hostFlag; +}; + + +template <class OS> +int +openFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault) + return -EFAULT; + + if (path == "/dev/sysdev0") { + // This is a memory-mapped high-resolution timer device on Alpha. + // We don't support it, so just punt. + DCOUT(SyscallWarnings) << "Ignoring open(" << path << ", ...)" << endl; + return -ENOENT; + } + + int tgtFlags = xc->getSyscallArg(1); + int mode = xc->getSyscallArg(2); + int hostFlags = 0; + + // translate open flags + for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { + if (tgtFlags & OS::openFlagTable[i].tgtFlag) { + tgtFlags &= ~OS::openFlagTable[i].tgtFlag; + hostFlags |= OS::openFlagTable[i].hostFlag; + } + } + + // any target flags left? + if (tgtFlags != 0) + cerr << "Syscall: open: cannot decode flags: " << tgtFlags << endl; + +#ifdef __CYGWIN32__ + hostFlags |= O_BINARY; +#endif + + // open the file + int fd = open(path.c_str(), hostFlags, mode); + + return (fd == -1) ? -errno : process->open_fd(fd); +} + + +template <class OS> +int +statFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault) + return -EFAULT; + + struct stat hostBuf; + int result = stat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +template <class OS> +int +lstatFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault) + return -EFAULT; + + struct stat hostBuf; + int result = lstat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); + + return 0; +} + +template <class OS> +int +fstatFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + // DPRINTFR(SyscallVerbose, "fstat(%d, ...)\n", fd); + + if (fd < 0) + return -EBADF; + + struct stat hostBuf; + int result = fstat(fd, &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +// +// We don't really handle mmap(). If the target is mmaping an +// anonymous region or /dev/zero, we can get away with doing basically +// nothing (since memory is initialized to zero and the simulator +// doesn't really check addresses anyway). Always print a warning, +// since this could be seriously broken if we're not mapping +// /dev/zero. +// +// Someday we should explicitly check for /dev/zero in open, flag the +// file descriptor, and fail (or implement!) a non-anonymous mmap to +// anything else. +// +template <class OS> +int +mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + Addr start = xc->getSyscallArg(0); + uint64_t length = xc->getSyscallArg(1); + // int prot = xc->getSyscallArg(2); + int flags = xc->getSyscallArg(3); + int fd = p->sim_fd(xc->getSyscallArg(4)); + // int offset = xc->getSyscallArg(5); + + if (start == 0) { + // user didn't give an address... pick one from our "mmap region" + start = p->mmap_base; + p->mmap_base += RoundUp<Addr>(length, VMPageSize); + } + + if (!(flags & OS::TGT_MAP_ANONYMOUS)) { + DPRINTF(SyscallWarnings, "Warning: allowing mmap of file @ fd %d. " + "This will break if not /dev/zero.", fd); + } + + return start; +} + + +template <class OS> +int +getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned resource = xc->getSyscallArg(0); + TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); + + switch (resource) { + case OS::RLIMIT_STACK: + // max stack size in bytes: make up a number (2MB for now) + rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; + break; + + default: + cerr << "getrlimitFunc: unimplemented resource " << resource << endl; + abort(); + break; + } + + rlp.copyOut(xc->mem); + return 0; +} + +// 1M usecs in 1 sec, for readability +const int one_million = 1000000; + +// seconds since the epoch (1/1/1970)... about a billion, by my reckoning +const unsigned seconds_since_epoch = 1000000000; + +// +// helper function: populate struct timeval with approximation of +// current elapsed time +// +template <class T1, class T2> +void +getElapsedTime(T1 &sec, T2 &usec) +{ + int cycles_per_usec = ticksPerSecond / one_million; + + int elapsed_usecs = curTick / cycles_per_usec; + sec = elapsed_usecs / one_million; + usec = elapsed_usecs % one_million; +} + + +template <class OS> +int +gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); + + getElapsedTime(tp->tv_sec, tp->tv_usec); + tp->tv_sec += seconds_since_epoch; + + tp.copyOut(xc->mem); + + return 0; +} + + +template <class OS> +int +getrusageFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN + TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); + + if (who != OS::RUSAGE_SELF) { + // don't really handle THREAD or CHILDREN, but just warn and + // plow ahead + DCOUT(SyscallWarnings) + << "Warning: getrusage() only supports RUSAGE_SELF." + << " Parameter " << who << " ignored." << endl; + } + + getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); + rup->ru_stime.tv_sec = 0; + rup->ru_stime.tv_usec = 0; + rup->ru_maxrss = 0; + rup->ru_ixrss = 0; + rup->ru_idrss = 0; + rup->ru_isrss = 0; + rup->ru_minflt = 0; + rup->ru_majflt = 0; + rup->ru_nswap = 0; + rup->ru_inblock = 0; + rup->ru_oublock = 0; + rup->ru_msgsnd = 0; + rup->ru_msgrcv = 0; + rup->ru_nsignals = 0; + rup->ru_nvcsw = 0; + rup->ru_nivcsw = 0; + + rup.copyOut(xc->mem); + + return 0; +} + + + +#endif // __SYSCALL_EMUL_HH__ |