syscall_emul.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,024 行 · 第 1/2 页
HH
1,024 行
/* * Copyright (c) 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Steven K. Reinhardt * Kevin T. Lim */#ifndef __SIM_SYSCALL_EMUL_HH__#define __SIM_SYSCALL_EMUL_HH__#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ defined(__FreeBSD__) || defined(__CYGWIN__))////// @file syscall_emul.hh////// This file defines objects used to emulate syscalls from the target/// application on the host machine.#include <errno.h>#include <string>#ifdef __CYGWIN32__#include <sys/fcntl.h> // for O_BINARY#endif#include <sys/stat.h>#include <fcntl.h>#include <sys/uio.h>#include "sim/host.hh" // for Addr#include "base/chunk_generator.hh"#include "base/intmath.hh" // for RoundUp#include "base/misc.hh"#include "base/trace.hh"#include "cpu/base.hh"#include "cpu/thread_context.hh"#include "mem/translating_port.hh"#include "mem/page_table.hh"#include "sim/process.hh"////// System call descriptor.///class SyscallDesc { public: /// Typedef for target syscall handler functions. typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, LiveProcess *, ThreadContext *); 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 ThreadContext 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, LiveProcess *proc, ThreadContext *tc);};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(TranslatingPort *memport) { memport->readBlob(addr, bufPtr, size); return true; // no EFAULT detection for now } // // copy data out of simulator space (write to target memory) // virtual bool copyOut(TranslatingPort *memport) { memport->writeBlob(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./////////////////////////////////////////////////////////////////////////// Handler for unimplemented syscalls that we haven't thought about.SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// 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.SyscallReturn ignoreFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target exit() handler: terminate simulation.SyscallReturn exitFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getpagesize() handler.SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target obreak() handler: set brk address.SyscallReturn obreakFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target close() handler.SyscallReturn closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target read() handler.SyscallReturn readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target write() handler.SyscallReturn writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target lseek() handler.SyscallReturn lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target _llseek() handler.SyscallReturn _llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target munmap() handler.SyscallReturn munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target gethostname() handler.SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target unlink() handler.SyscallReturn unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target rename() handler.SyscallReturn renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target truncate() handler.SyscallReturn truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target ftruncate() handler.SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target chown() handler.SyscallReturn chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target fchown() handler.SyscallReturn fchownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target dup() handler.SyscallReturn dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc);/// Target fnctl() handler.SyscallReturn fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc);/// Target fcntl64() handler.SyscallReturn fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc);/// Target setuid() handler.SyscallReturn setuidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getpid() handler.SyscallReturn getpidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getuid() handler.SyscallReturn getuidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getgid() handler.SyscallReturn getgidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getppid() handler.SyscallReturn getppidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target geteuid() handler.SyscallReturn geteuidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getegid() handler.SyscallReturn getegidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Pseudo Funcs - These functions use a different return convension,/// returning a second value in a register other than the normal return registerSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc);/// Target getpidPseudo() handler.SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getuidPseudo() handler.SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// Target getgidPseudo() handler.SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc);/// A readable name for 1,000,000, for converting microseconds to seconds.const int one_million = 1000000;/// Approximate seconds since the epoch (1/1/1970). About a billion,/// by my reckoning. We want to keep this a constant (not use the/// real-world time) to keep simulations repeatable.const unsigned seconds_since_epoch = 1000000000;/// Helper function to convert current elapsed time to seconds and/// microseconds.template <class T1, class T2>voidgetElapsedTime(T1 &sec, T2 &usec){ int elapsed_usecs = curTick / Clock::Int::us; sec = elapsed_usecs / one_million; usec = elapsed_usecs % one_million;}////////////////////////////////////////////////////////////////////////// The following emulation functions are generic, but need to be// templated to account for differences in types, constants, etc.////////////////////////////////////////////////////////////////////////#if NO_STAT64 typedef struct stat hst_stat; typedef struct stat hst_stat64;#else typedef struct stat hst_stat; typedef struct stat64 hst_stat64;#endif//// Helper function to convert a host stat buffer to a target stat//// buffer. Also copies the target buffer out to the simulated//// memory space. Used by stat(), fstat(), and lstat().template <typename target_stat, typename host_stat>static voidconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false){ using namespace TheISA; if (fakeTTY) tgt->st_dev = 0xA; else tgt->st_dev = host->st_dev; tgt->st_dev = htog(tgt->st_dev); tgt->st_ino = host->st_ino; tgt->st_ino = htog(tgt->st_ino); tgt->st_mode = host->st_mode; tgt->st_mode = htog(tgt->st_mode); tgt->st_nlink = host->st_nlink; tgt->st_nlink = htog(tgt->st_nlink); tgt->st_uid = host->st_uid; tgt->st_uid = htog(tgt->st_uid); tgt->st_gid = host->st_gid; tgt->st_gid = htog(tgt->st_gid); if (fakeTTY) tgt->st_rdev = 0x880d; else tgt->st_rdev = host->st_rdev; tgt->st_rdev = htog(tgt->st_rdev); tgt->st_size = host->st_size; tgt->st_size = htog(tgt->st_size); tgt->st_atimeX = host->st_atime; tgt->st_atimeX = htog(tgt->st_atimeX); tgt->st_mtimeX = host->st_mtime; tgt->st_mtimeX = htog(tgt->st_mtimeX); tgt->st_ctimeX = host->st_ctime; tgt->st_ctimeX = htog(tgt->st_ctimeX); // Force the block size to be 8k. This helps to ensure buffered io works // consistently across different hosts. tgt->st_blksize = 0x2000; tgt->st_blksize = htog(tgt->st_blksize); tgt->st_blocks = host->st_blocks; tgt->st_blocks = htog(tgt->st_blocks);}// Same for stat64template <typename target_stat, typename host_stat64>static voidconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false){ using namespace TheISA; convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);#if defined(STAT_HAVE_NSEC) tgt->st_atime_nsec = host->st_atime_nsec; tgt->st_atime_nsec = htog(tgt->st_atime_nsec); tgt->st_mtime_nsec = host->st_mtime_nsec; tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec); tgt->st_ctime_nsec = host->st_ctime_nsec; tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec);#else tgt->st_atime_nsec = 0; tgt->st_mtime_nsec = 0; tgt->st_ctime_nsec = 0;#endif}//Here are a couple convenience functionstemplate<class OS>static voidcopyOutStatBuf(TranslatingPort * mem, Addr addr, hst_stat *host, bool fakeTTY = false){ typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; tgt_stat_buf tgt(addr); convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); tgt.copyOut(mem);}template<class OS>static voidcopyOutStat64Buf(TranslatingPort * mem, Addr addr, hst_stat64 *host, bool fakeTTY = false){ typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; tgt_stat_buf tgt(addr); convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); tgt.copyOut(mem);}/// Target ioctl() handler. For the most part, programs call ioctl()/// only to find out if their stdout is a tty, to determine whether to/// do line or block buffering.template <class OS>SyscallReturnioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc){ int fd = tc->getSyscallArg(0); unsigned req = tc->getSyscallArg(1); DPRINTF(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_: case OS::TIOCGETS_: case OS::TIOCGETA_: return -ENOTTY; default: fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", fd, req, tc->readPC()); }}/// Target open() handler.template <class OS>SyscallReturnopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc){ std::string path; if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 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. warn("Ignoring open(%s, ...)\n", path); return -ENOENT; } int tgtFlags = tc->getSyscallArg(1); int mode = tc->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) warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);#ifdef __CYGWIN32__ hostFlags |= O_BINARY;#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?