syscall_emul.hh revision 10484
1/* 2 * Copyright (c) 2012-2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2003-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Steve Reinhardt 41 * Kevin Lim 42 */ 43 44#ifndef __SIM_SYSCALL_EMUL_HH__ 45#define __SIM_SYSCALL_EMUL_HH__ 46 47#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 48 defined(__FreeBSD__) || defined(__CYGWIN__) || \ 49 defined(__NetBSD__)) 50 51/// 52/// @file syscall_emul.hh 53/// 54/// This file defines objects used to emulate syscalls from the target 55/// application on the host machine. 56 57#ifdef __CYGWIN32__ 58#include <sys/fcntl.h> // for O_BINARY 59#endif 60#include <sys/stat.h> 61#include <sys/time.h> 62#include <sys/uio.h> 63#include <fcntl.h> 64 65#include <cerrno> 66#include <string> 67 68#include "base/chunk_generator.hh" 69#include "base/intmath.hh" // for RoundUp 70#include "base/misc.hh" 71#include "base/trace.hh" 72#include "base/types.hh" 73#include "config/the_isa.hh" 74#include "cpu/base.hh" 75#include "cpu/thread_context.hh" 76#include "debug/SyscallVerbose.hh" 77#include "mem/page_table.hh" 78#include "mem/se_translating_port_proxy.hh" 79#include "sim/byteswap.hh" 80#include "sim/process.hh" 81#include "sim/syscallreturn.hh" 82#include "sim/system.hh" 83 84/// 85/// System call descriptor. 86/// 87class SyscallDesc { 88 89 public: 90 91 /// Typedef for target syscall handler functions. 92 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 93 LiveProcess *, ThreadContext *); 94 95 const char *name; //!< Syscall name (e.g., "open"). 96 FuncPtr funcPtr; //!< Pointer to emulation function. 97 int flags; //!< Flags (see Flags enum). 98 99 /// Flag values for controlling syscall behavior. 100 enum Flags { 101 /// Don't set return regs according to funcPtr return value. 102 /// Used for syscalls with non-standard return conventions 103 /// that explicitly set the ThreadContext regs (e.g., 104 /// sigreturn). 105 SuppressReturnValue = 1 106 }; 107 108 /// Constructor. 109 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 110 : name(_name), funcPtr(_funcPtr), flags(_flags) 111 { 112 } 113 114 /// Emulate the syscall. Public interface for calling through funcPtr. 115 void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 116}; 117 118 119class BaseBufferArg { 120 121 public: 122 123 BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 124 { 125 bufPtr = new uint8_t[size]; 126 // clear out buffer: in case we only partially populate this, 127 // and then do a copyOut(), we want to make sure we don't 128 // introduce any random junk into the simulated address space 129 memset(bufPtr, 0, size); 130 } 131 132 virtual ~BaseBufferArg() { delete [] bufPtr; } 133 134 // 135 // copy data into simulator space (read from target memory) 136 // 137 virtual bool copyIn(SETranslatingPortProxy &memproxy) 138 { 139 memproxy.readBlob(addr, bufPtr, size); 140 return true; // no EFAULT detection for now 141 } 142 143 // 144 // copy data out of simulator space (write to target memory) 145 // 146 virtual bool copyOut(SETranslatingPortProxy &memproxy) 147 { 148 memproxy.writeBlob(addr, bufPtr, size); 149 return true; // no EFAULT detection for now 150 } 151 152 protected: 153 Addr addr; 154 int size; 155 uint8_t *bufPtr; 156}; 157 158 159class BufferArg : public BaseBufferArg 160{ 161 public: 162 BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 163 void *bufferPtr() { return bufPtr; } 164}; 165 166template <class T> 167class TypedBufferArg : public BaseBufferArg 168{ 169 public: 170 // user can optionally specify a specific number of bytes to 171 // allocate to deal with those structs that have variable-size 172 // arrays at the end 173 TypedBufferArg(Addr _addr, int _size = sizeof(T)) 174 : BaseBufferArg(_addr, _size) 175 { } 176 177 // type case 178 operator T*() { return (T *)bufPtr; } 179 180 // dereference operators 181 T &operator*() { return *((T *)bufPtr); } 182 T* operator->() { return (T *)bufPtr; } 183 T &operator[](int i) { return ((T *)bufPtr)[i]; } 184}; 185 186////////////////////////////////////////////////////////////////////// 187// 188// The following emulation functions are generic enough that they 189// don't need to be recompiled for different emulated OS's. They are 190// defined in sim/syscall_emul.cc. 191// 192////////////////////////////////////////////////////////////////////// 193 194 195/// Handler for unimplemented syscalls that we haven't thought about. 196SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 197 LiveProcess *p, ThreadContext *tc); 198 199/// Handler for unimplemented syscalls that we never intend to 200/// implement (signal handling, etc.) and should not affect the correct 201/// behavior of the program. Print a warning only if the appropriate 202/// trace flag is enabled. Return success to the target program. 203SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 204 LiveProcess *p, ThreadContext *tc); 205SyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num, 206 LiveProcess *p, ThreadContext *tc); 207 208/// Target exit() handler: terminate current context. 209SyscallReturn exitFunc(SyscallDesc *desc, int num, 210 LiveProcess *p, ThreadContext *tc); 211 212/// Target exit_group() handler: terminate simulation. (exit all threads) 213SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 214 LiveProcess *p, ThreadContext *tc); 215 216/// Target getpagesize() handler. 217SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 218 LiveProcess *p, ThreadContext *tc); 219 220/// Target brk() handler: set brk address. 221SyscallReturn brkFunc(SyscallDesc *desc, int num, 222 LiveProcess *p, ThreadContext *tc); 223 224/// Target close() handler. 225SyscallReturn closeFunc(SyscallDesc *desc, int num, 226 LiveProcess *p, ThreadContext *tc); 227 228/// Target read() handler. 229SyscallReturn readFunc(SyscallDesc *desc, int num, 230 LiveProcess *p, ThreadContext *tc); 231 232/// Target write() handler. 233SyscallReturn writeFunc(SyscallDesc *desc, int num, 234 LiveProcess *p, ThreadContext *tc); 235 236/// Target lseek() handler. 237SyscallReturn lseekFunc(SyscallDesc *desc, int num, 238 LiveProcess *p, ThreadContext *tc); 239 240/// Target _llseek() handler. 241SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 242 LiveProcess *p, ThreadContext *tc); 243 244/// Target munmap() handler. 245SyscallReturn munmapFunc(SyscallDesc *desc, int num, 246 LiveProcess *p, ThreadContext *tc); 247 248/// Target gethostname() handler. 249SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 250 LiveProcess *p, ThreadContext *tc); 251 252/// Target getcwd() handler. 253SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 254 LiveProcess *p, ThreadContext *tc); 255 256/// Target readlink() handler. 257SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 258 LiveProcess *p, ThreadContext *tc, 259 int index = 0); 260SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 261 LiveProcess *p, ThreadContext *tc); 262 263/// Target unlink() handler. 264SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 265 LiveProcess *p, ThreadContext *tc); 266 267/// Target mkdir() handler. 268SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 269 LiveProcess *p, ThreadContext *tc); 270 271/// Target rename() handler. 272SyscallReturn renameFunc(SyscallDesc *desc, int num, 273 LiveProcess *p, ThreadContext *tc); 274 275 276/// Target truncate() handler. 277SyscallReturn truncateFunc(SyscallDesc *desc, int num, 278 LiveProcess *p, ThreadContext *tc); 279 280 281/// Target ftruncate() handler. 282SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 283 LiveProcess *p, ThreadContext *tc); 284 285 286/// Target truncate64() handler. 287SyscallReturn truncate64Func(SyscallDesc *desc, int num, 288 LiveProcess *p, ThreadContext *tc); 289 290/// Target ftruncate64() handler. 291SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 292 LiveProcess *p, ThreadContext *tc); 293 294 295/// Target umask() handler. 296SyscallReturn umaskFunc(SyscallDesc *desc, int num, 297 LiveProcess *p, ThreadContext *tc); 298 299 300/// Target chown() handler. 301SyscallReturn chownFunc(SyscallDesc *desc, int num, 302 LiveProcess *p, ThreadContext *tc); 303 304 305/// Target fchown() handler. 306SyscallReturn fchownFunc(SyscallDesc *desc, int num, 307 LiveProcess *p, ThreadContext *tc); 308 309/// Target dup() handler. 310SyscallReturn dupFunc(SyscallDesc *desc, int num, 311 LiveProcess *process, ThreadContext *tc); 312 313/// Target fnctl() handler. 314SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 315 LiveProcess *process, ThreadContext *tc); 316 317/// Target fcntl64() handler. 318SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 319 LiveProcess *process, ThreadContext *tc); 320 321/// Target setuid() handler. 322SyscallReturn setuidFunc(SyscallDesc *desc, int num, 323 LiveProcess *p, ThreadContext *tc); 324 325/// Target getpid() handler. 326SyscallReturn getpidFunc(SyscallDesc *desc, int num, 327 LiveProcess *p, ThreadContext *tc); 328 329/// Target getuid() handler. 330SyscallReturn getuidFunc(SyscallDesc *desc, int num, 331 LiveProcess *p, ThreadContext *tc); 332 333/// Target getgid() handler. 334SyscallReturn getgidFunc(SyscallDesc *desc, int num, 335 LiveProcess *p, ThreadContext *tc); 336 337/// Target getppid() handler. 338SyscallReturn getppidFunc(SyscallDesc *desc, int num, 339 LiveProcess *p, ThreadContext *tc); 340 341/// Target geteuid() handler. 342SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 343 LiveProcess *p, ThreadContext *tc); 344 345/// Target getegid() handler. 346SyscallReturn getegidFunc(SyscallDesc *desc, int num, 347 LiveProcess *p, ThreadContext *tc); 348 349/// Target clone() handler. 350SyscallReturn cloneFunc(SyscallDesc *desc, int num, 351 LiveProcess *p, ThreadContext *tc); 352 353/// Target access() handler 354SyscallReturn accessFunc(SyscallDesc *desc, int num, 355 LiveProcess *p, ThreadContext *tc); 356SyscallReturn accessFunc(SyscallDesc *desc, int num, 357 LiveProcess *p, ThreadContext *tc, 358 int index); 359 360/// Futex system call 361/// Implemented by Daniel Sanchez 362/// Used by printf's in multi-threaded apps 363template <class OS> 364SyscallReturn 365futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 366 ThreadContext *tc) 367{ 368 int index_uaddr = 0; 369 int index_op = 1; 370 int index_val = 2; 371 int index_timeout = 3; 372 373 uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 374 int op = process->getSyscallArg(tc, index_op); 375 int val = process->getSyscallArg(tc, index_val); 376 uint64_t timeout = process->getSyscallArg(tc, index_timeout); 377 378 std::map<uint64_t, std::list<ThreadContext *> * > 379 &futex_map = tc->getSystemPtr()->futexMap; 380 381 DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 382 uaddr, op, val); 383 384 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 385 386 if (op == OS::TGT_FUTEX_WAIT) { 387 if (timeout != 0) { 388 warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 389 "we'll wait indefinitely"); 390 } 391 392 uint8_t *buf = new uint8_t[sizeof(int)]; 393 tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 394 int mem_val = *((int *)buf); 395 delete buf; 396 397 if(val != mem_val) { 398 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 399 "expected: %d\n", mem_val, val); 400 return -OS::TGT_EWOULDBLOCK; 401 } 402 403 // Queue the thread context 404 std::list<ThreadContext *> * tcWaitList; 405 if (futex_map.count(uaddr)) { 406 tcWaitList = futex_map.find(uaddr)->second; 407 } else { 408 tcWaitList = new std::list<ThreadContext *>(); 409 futex_map.insert(std::pair< uint64_t, 410 std::list<ThreadContext *> * >(uaddr, tcWaitList)); 411 } 412 tcWaitList->push_back(tc); 413 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 414 "thread context\n"); 415 tc->suspend(); 416 return 0; 417 } else if (op == OS::TGT_FUTEX_WAKE){ 418 int wokenUp = 0; 419 std::list<ThreadContext *> * tcWaitList; 420 if (futex_map.count(uaddr)) { 421 tcWaitList = futex_map.find(uaddr)->second; 422 while (tcWaitList->size() > 0 && wokenUp < val) { 423 tcWaitList->front()->activate(); 424 tcWaitList->pop_front(); 425 wokenUp++; 426 } 427 if(tcWaitList->empty()) { 428 futex_map.erase(uaddr); 429 delete tcWaitList; 430 } 431 } 432 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 433 "thread contexts\n", wokenUp); 434 return wokenUp; 435 } else { 436 warn("sys_futex: op %d is not implemented, just returning...", op); 437 return 0; 438 } 439 440} 441 442/// Target getdents() handler. 443SyscallReturn getdentsFunc(SyscallDesc *desc, int num, 444 LiveProcess *process, ThreadContext *tc); 445 446/// Target getdents64() handler. 447SyscallReturn getdents64Func(SyscallDesc *desc, int num, 448 LiveProcess *process, ThreadContext *tc); 449 450 451/// Pseudo Funcs - These functions use a different return convension, 452/// returning a second value in a register other than the normal return register 453SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 454 LiveProcess *process, ThreadContext *tc); 455 456/// Target getpidPseudo() handler. 457SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 458 LiveProcess *p, ThreadContext *tc); 459 460/// Target getuidPseudo() handler. 461SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 462 LiveProcess *p, ThreadContext *tc); 463 464/// Target getgidPseudo() handler. 465SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 466 LiveProcess *p, ThreadContext *tc); 467 468 469/// A readable name for 1,000,000, for converting microseconds to seconds. 470const int one_million = 1000000; 471 472/// Approximate seconds since the epoch (1/1/1970). About a billion, 473/// by my reckoning. We want to keep this a constant (not use the 474/// real-world time) to keep simulations repeatable. 475const unsigned seconds_since_epoch = 1000000000; 476 477/// Helper function to convert current elapsed time to seconds and 478/// microseconds. 479template <class T1, class T2> 480void 481getElapsedTime(T1 &sec, T2 &usec) 482{ 483 int elapsed_usecs = curTick() / SimClock::Int::us; 484 sec = elapsed_usecs / one_million; 485 usec = elapsed_usecs % one_million; 486} 487 488////////////////////////////////////////////////////////////////////// 489// 490// The following emulation functions are generic, but need to be 491// templated to account for differences in types, constants, etc. 492// 493////////////////////////////////////////////////////////////////////// 494 495#if NO_STAT64 496 typedef struct stat hst_stat; 497 typedef struct stat hst_stat64; 498#else 499 typedef struct stat hst_stat; 500 typedef struct stat64 hst_stat64; 501#endif 502 503//// Helper function to convert a host stat buffer to a target stat 504//// buffer. Also copies the target buffer out to the simulated 505//// memory space. Used by stat(), fstat(), and lstat(). 506 507template <typename target_stat, typename host_stat> 508static void 509convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 510{ 511 using namespace TheISA; 512 513 if (fakeTTY) 514 tgt->st_dev = 0xA; 515 else 516 tgt->st_dev = host->st_dev; 517 tgt->st_dev = TheISA::htog(tgt->st_dev); 518 tgt->st_ino = host->st_ino; 519 tgt->st_ino = TheISA::htog(tgt->st_ino); 520 tgt->st_mode = host->st_mode; 521 if (fakeTTY) { 522 // Claim to be a character device 523 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 524 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 525 } 526 tgt->st_mode = TheISA::htog(tgt->st_mode); 527 tgt->st_nlink = host->st_nlink; 528 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 529 tgt->st_uid = host->st_uid; 530 tgt->st_uid = TheISA::htog(tgt->st_uid); 531 tgt->st_gid = host->st_gid; 532 tgt->st_gid = TheISA::htog(tgt->st_gid); 533 if (fakeTTY) 534 tgt->st_rdev = 0x880d; 535 else 536 tgt->st_rdev = host->st_rdev; 537 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 538 tgt->st_size = host->st_size; 539 tgt->st_size = TheISA::htog(tgt->st_size); 540 tgt->st_atimeX = host->st_atime; 541 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 542 tgt->st_mtimeX = host->st_mtime; 543 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 544 tgt->st_ctimeX = host->st_ctime; 545 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 546 // Force the block size to be 8k. This helps to ensure buffered io works 547 // consistently across different hosts. 548 tgt->st_blksize = 0x2000; 549 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 550 tgt->st_blocks = host->st_blocks; 551 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 552} 553 554// Same for stat64 555 556template <typename target_stat, typename host_stat64> 557static void 558convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 559{ 560 using namespace TheISA; 561 562 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 563#if defined(STAT_HAVE_NSEC) 564 tgt->st_atime_nsec = host->st_atime_nsec; 565 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 566 tgt->st_mtime_nsec = host->st_mtime_nsec; 567 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 568 tgt->st_ctime_nsec = host->st_ctime_nsec; 569 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 570#else 571 tgt->st_atime_nsec = 0; 572 tgt->st_mtime_nsec = 0; 573 tgt->st_ctime_nsec = 0; 574#endif 575} 576 577//Here are a couple convenience functions 578template<class OS> 579static void 580copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 581 hst_stat *host, bool fakeTTY = false) 582{ 583 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 584 tgt_stat_buf tgt(addr); 585 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 586 tgt.copyOut(mem); 587} 588 589template<class OS> 590static void 591copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 592 hst_stat64 *host, bool fakeTTY = false) 593{ 594 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 595 tgt_stat_buf tgt(addr); 596 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 597 tgt.copyOut(mem); 598} 599 600/// Target ioctl() handler. For the most part, programs call ioctl() 601/// only to find out if their stdout is a tty, to determine whether to 602/// do line or block buffering. We always claim that output fds are 603/// not TTYs to provide repeatable results. 604template <class OS> 605SyscallReturn 606ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 607 ThreadContext *tc) 608{ 609 int index = 0; 610 int fd = process->getSyscallArg(tc, index); 611 unsigned req = process->getSyscallArg(tc, index); 612 613 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 614 615 if (fd < 0 || process->sim_fd(fd) < 0) { 616 // doesn't map to any simulator fd: not a valid target fd 617 return -EBADF; 618 } 619 620 if (OS::isTtyReq(req)) { 621 return -ENOTTY; 622 } 623 624 warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 625 fd, req, tc->pcState()); 626 return -ENOTTY; 627} 628 629template <class OS> 630static SyscallReturn 631openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 632 ThreadContext *tc, int index) 633{ 634 std::string path; 635 636 if (!tc->getMemProxy().tryReadString(path, 637 process->getSyscallArg(tc, index))) 638 return -EFAULT; 639 640 if (path == "/dev/sysdev0") { 641 // This is a memory-mapped high-resolution timer device on Alpha. 642 // We don't support it, so just punt. 643 warn("Ignoring open(%s, ...)\n", path); 644 return -ENOENT; 645 } 646 647 int tgtFlags = process->getSyscallArg(tc, index); 648 int mode = process->getSyscallArg(tc, index); 649 int hostFlags = 0; 650 651 // translate open flags 652 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 653 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 654 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 655 hostFlags |= OS::openFlagTable[i].hostFlag; 656 } 657 } 658 659 // any target flags left? 660 if (tgtFlags != 0) 661 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 662 663#ifdef __CYGWIN32__ 664 hostFlags |= O_BINARY; 665#endif 666 667 // Adjust path for current working directory 668 path = process->fullPath(path); 669 670 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 671 672 int fd; 673 int local_errno; 674 if (startswith(path, "/proc/") || startswith(path, "/system/") || 675 startswith(path, "/platform/") || startswith(path, "/sys/")) { 676 // It's a proc/sys entry and requires special handling 677 fd = OS::openSpecialFile(path, process, tc); 678 local_errno = ENOENT; 679 } else { 680 // open the file 681 fd = open(path.c_str(), hostFlags, mode); 682 local_errno = errno; 683 } 684 685 if (fd == -1) 686 return -local_errno; 687 688 return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false); 689} 690 691/// Target open() handler. 692template <class OS> 693SyscallReturn 694openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 695 ThreadContext *tc) 696{ 697 return openFunc<OS>(desc, callnum, process, tc, 0); 698} 699 700/// Target openat() handler. 701template <class OS> 702SyscallReturn 703openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 704 ThreadContext *tc) 705{ 706 int index = 0; 707 int dirfd = process->getSyscallArg(tc, index); 708 if (dirfd != OS::TGT_AT_FDCWD) 709 warn("openat: first argument not AT_FDCWD; unlikely to work"); 710 return openFunc<OS>(desc, callnum, process, tc, 1); 711} 712 713/// Target facessat() handler 714template <class OS> 715SyscallReturn 716faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 717 ThreadContext *tc) 718{ 719 int index = 0; 720 int dirfd = process->getSyscallArg(tc, index); 721 if (dirfd != OS::TGT_AT_FDCWD) 722 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 723 return accessFunc(desc, callnum, process, tc, 1); 724} 725 726/// Target readlinkat() handler 727template <class OS> 728SyscallReturn 729readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 730 ThreadContext *tc) 731{ 732 int index = 0; 733 int dirfd = process->getSyscallArg(tc, index); 734 if (dirfd != OS::TGT_AT_FDCWD) 735 warn("openat: first argument not AT_FDCWD; unlikely to work"); 736 return readlinkFunc(desc, callnum, process, tc, 1); 737} 738 739/// Target sysinfo() handler. 740template <class OS> 741SyscallReturn 742sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 743 ThreadContext *tc) 744{ 745 746 int index = 0; 747 TypedBufferArg<typename OS::tgt_sysinfo> 748 sysinfo(process->getSyscallArg(tc, index)); 749 750 sysinfo->uptime=seconds_since_epoch; 751 sysinfo->totalram=process->system->memSize(); 752 753 sysinfo.copyOut(tc->getMemProxy()); 754 755 return 0; 756} 757 758/// Target chmod() handler. 759template <class OS> 760SyscallReturn 761chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 762 ThreadContext *tc) 763{ 764 std::string path; 765 766 int index = 0; 767 if (!tc->getMemProxy().tryReadString(path, 768 process->getSyscallArg(tc, index))) { 769 return -EFAULT; 770 } 771 772 uint32_t mode = process->getSyscallArg(tc, index); 773 mode_t hostMode = 0; 774 775 // XXX translate mode flags via OS::something??? 776 hostMode = mode; 777 778 // Adjust path for current working directory 779 path = process->fullPath(path); 780 781 // do the chmod 782 int result = chmod(path.c_str(), hostMode); 783 if (result < 0) 784 return -errno; 785 786 return 0; 787} 788 789 790/// Target fchmod() handler. 791template <class OS> 792SyscallReturn 793fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 794 ThreadContext *tc) 795{ 796 int index = 0; 797 int fd = process->getSyscallArg(tc, index); 798 if (fd < 0 || process->sim_fd(fd) < 0) { 799 // doesn't map to any simulator fd: not a valid target fd 800 return -EBADF; 801 } 802 803 uint32_t mode = process->getSyscallArg(tc, index); 804 mode_t hostMode = 0; 805 806 // XXX translate mode flags via OS::someting??? 807 hostMode = mode; 808 809 // do the fchmod 810 int result = fchmod(process->sim_fd(fd), hostMode); 811 if (result < 0) 812 return -errno; 813 814 return 0; 815} 816 817/// Target mremap() handler. 818template <class OS> 819SyscallReturn 820mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 821{ 822 int index = 0; 823 Addr start = process->getSyscallArg(tc, index); 824 uint64_t old_length = process->getSyscallArg(tc, index); 825 uint64_t new_length = process->getSyscallArg(tc, index); 826 uint64_t flags = process->getSyscallArg(tc, index); 827 uint64_t provided_address = 0; 828 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 829 830 if (use_provided_address) 831 provided_address = process->getSyscallArg(tc, index); 832 833 if ((start % TheISA::PageBytes != 0) || 834 (new_length % TheISA::PageBytes != 0) || 835 (provided_address % TheISA::PageBytes != 0)) { 836 warn("mremap failing: arguments not page aligned"); 837 return -EINVAL; 838 } 839 840 if (new_length > old_length) { 841 if ((start + old_length) == process->mmap_end && 842 (!use_provided_address || provided_address == start)) { 843 uint64_t diff = new_length - old_length; 844 process->allocateMem(process->mmap_end, diff); 845 process->mmap_end += diff; 846 return start; 847 } else { 848 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 849 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 850 return -ENOMEM; 851 } else { 852 uint64_t new_start = use_provided_address ? 853 provided_address : process->mmap_end; 854 process->pTable->remap(start, old_length, new_start); 855 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 856 new_start, new_start + new_length, 857 new_length - old_length); 858 // add on the remaining unallocated pages 859 process->allocateMem(new_start + old_length, 860 new_length - old_length, 861 use_provided_address /* clobber */); 862 if (!use_provided_address) 863 process->mmap_end += new_length; 864 if (use_provided_address && 865 new_start + new_length > process->mmap_end) { 866 // something fishy going on here, at least notify the user 867 // @todo: increase mmap_end? 868 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 869 } 870 warn("returning %08p as start\n", new_start); 871 return new_start; 872 } 873 } 874 } else { 875 if (use_provided_address && provided_address != start) 876 process->pTable->remap(start, new_length, provided_address); 877 process->pTable->unmap(start + new_length, old_length - new_length); 878 return use_provided_address ? provided_address : start; 879 } 880} 881 882/// Target stat() handler. 883template <class OS> 884SyscallReturn 885statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 886 ThreadContext *tc) 887{ 888 std::string path; 889 890 int index = 0; 891 if (!tc->getMemProxy().tryReadString(path, 892 process->getSyscallArg(tc, index))) { 893 return -EFAULT; 894 } 895 Addr bufPtr = process->getSyscallArg(tc, index); 896 897 // Adjust path for current working directory 898 path = process->fullPath(path); 899 900 struct stat hostBuf; 901 int result = stat(path.c_str(), &hostBuf); 902 903 if (result < 0) 904 return -errno; 905 906 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 907 908 return 0; 909} 910 911 912/// Target stat64() handler. 913template <class OS> 914SyscallReturn 915stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 916 ThreadContext *tc) 917{ 918 std::string path; 919 920 int index = 0; 921 if (!tc->getMemProxy().tryReadString(path, 922 process->getSyscallArg(tc, index))) 923 return -EFAULT; 924 Addr bufPtr = process->getSyscallArg(tc, index); 925 926 // Adjust path for current working directory 927 path = process->fullPath(path); 928 929#if NO_STAT64 930 struct stat hostBuf; 931 int result = stat(path.c_str(), &hostBuf); 932#else 933 struct stat64 hostBuf; 934 int result = stat64(path.c_str(), &hostBuf); 935#endif 936 937 if (result < 0) 938 return -errno; 939 940 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 941 942 return 0; 943} 944 945 946/// Target fstatat64() handler. 947template <class OS> 948SyscallReturn 949fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 950 ThreadContext *tc) 951{ 952 int index = 0; 953 int dirfd = process->getSyscallArg(tc, index); 954 if (dirfd != OS::TGT_AT_FDCWD) 955 warn("openat: first argument not AT_FDCWD; unlikely to work"); 956 957 std::string path; 958 if (!tc->getMemProxy().tryReadString(path, 959 process->getSyscallArg(tc, index))) 960 return -EFAULT; 961 Addr bufPtr = process->getSyscallArg(tc, index); 962 963 // Adjust path for current working directory 964 path = process->fullPath(path); 965 966#if NO_STAT64 967 struct stat hostBuf; 968 int result = stat(path.c_str(), &hostBuf); 969#else 970 struct stat64 hostBuf; 971 int result = stat64(path.c_str(), &hostBuf); 972#endif 973 974 if (result < 0) 975 return -errno; 976 977 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 978 979 return 0; 980} 981 982 983/// Target fstat64() handler. 984template <class OS> 985SyscallReturn 986fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 987 ThreadContext *tc) 988{ 989 int index = 0; 990 int fd = process->getSyscallArg(tc, index); 991 Addr bufPtr = process->getSyscallArg(tc, index); 992 if (fd < 0 || process->sim_fd(fd) < 0) { 993 // doesn't map to any simulator fd: not a valid target fd 994 return -EBADF; 995 } 996 997#if NO_STAT64 998 struct stat hostBuf; 999 int result = fstat(process->sim_fd(fd), &hostBuf); 1000#else 1001 struct stat64 hostBuf; 1002 int result = fstat64(process->sim_fd(fd), &hostBuf); 1003#endif 1004 1005 if (result < 0) 1006 return -errno; 1007 1008 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 1009 1010 return 0; 1011} 1012 1013 1014/// Target lstat() handler. 1015template <class OS> 1016SyscallReturn 1017lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1018 ThreadContext *tc) 1019{ 1020 std::string path; 1021 1022 int index = 0; 1023 if (!tc->getMemProxy().tryReadString(path, 1024 process->getSyscallArg(tc, index))) { 1025 return -EFAULT; 1026 } 1027 Addr bufPtr = process->getSyscallArg(tc, index); 1028 1029 // Adjust path for current working directory 1030 path = process->fullPath(path); 1031 1032 struct stat hostBuf; 1033 int result = lstat(path.c_str(), &hostBuf); 1034 1035 if (result < 0) 1036 return -errno; 1037 1038 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1039 1040 return 0; 1041} 1042 1043/// Target lstat64() handler. 1044template <class OS> 1045SyscallReturn 1046lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1047 ThreadContext *tc) 1048{ 1049 std::string path; 1050 1051 int index = 0; 1052 if (!tc->getMemProxy().tryReadString(path, 1053 process->getSyscallArg(tc, index))) { 1054 return -EFAULT; 1055 } 1056 Addr bufPtr = process->getSyscallArg(tc, index); 1057 1058 // Adjust path for current working directory 1059 path = process->fullPath(path); 1060 1061#if NO_STAT64 1062 struct stat hostBuf; 1063 int result = lstat(path.c_str(), &hostBuf); 1064#else 1065 struct stat64 hostBuf; 1066 int result = lstat64(path.c_str(), &hostBuf); 1067#endif 1068 1069 if (result < 0) 1070 return -errno; 1071 1072 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1073 1074 return 0; 1075} 1076 1077/// Target fstat() handler. 1078template <class OS> 1079SyscallReturn 1080fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1081 ThreadContext *tc) 1082{ 1083 int index = 0; 1084 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1085 Addr bufPtr = process->getSyscallArg(tc, index); 1086 1087 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 1088 1089 if (fd < 0) 1090 return -EBADF; 1091 1092 struct stat hostBuf; 1093 int result = fstat(fd, &hostBuf); 1094 1095 if (result < 0) 1096 return -errno; 1097 1098 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 1099 1100 return 0; 1101} 1102 1103 1104/// Target statfs() handler. 1105template <class OS> 1106SyscallReturn 1107statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1108 ThreadContext *tc) 1109{ 1110 std::string path; 1111 1112 int index = 0; 1113 if (!tc->getMemProxy().tryReadString(path, 1114 process->getSyscallArg(tc, index))) { 1115 return -EFAULT; 1116 } 1117 Addr bufPtr = process->getSyscallArg(tc, index); 1118 1119 // Adjust path for current working directory 1120 path = process->fullPath(path); 1121 1122 struct statfs hostBuf; 1123 int result = statfs(path.c_str(), &hostBuf); 1124 1125 if (result < 0) 1126 return -errno; 1127 1128 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1129 1130 return 0; 1131} 1132 1133 1134/// Target fstatfs() handler. 1135template <class OS> 1136SyscallReturn 1137fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1138 ThreadContext *tc) 1139{ 1140 int index = 0; 1141 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1142 Addr bufPtr = process->getSyscallArg(tc, index); 1143 1144 if (fd < 0) 1145 return -EBADF; 1146 1147 struct statfs hostBuf; 1148 int result = fstatfs(fd, &hostBuf); 1149 1150 if (result < 0) 1151 return -errno; 1152 1153 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1154 1155 return 0; 1156} 1157 1158 1159/// Target writev() handler. 1160template <class OS> 1161SyscallReturn 1162writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1163 ThreadContext *tc) 1164{ 1165 int index = 0; 1166 int fd = process->getSyscallArg(tc, index); 1167 if (fd < 0 || process->sim_fd(fd) < 0) { 1168 // doesn't map to any simulator fd: not a valid target fd 1169 return -EBADF; 1170 } 1171 1172 SETranslatingPortProxy &p = tc->getMemProxy(); 1173 uint64_t tiov_base = process->getSyscallArg(tc, index); 1174 size_t count = process->getSyscallArg(tc, index); 1175 struct iovec hiov[count]; 1176 for (size_t i = 0; i < count; ++i) { 1177 typename OS::tgt_iovec tiov; 1178 1179 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1180 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1181 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1182 hiov[i].iov_base = new char [hiov[i].iov_len]; 1183 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1184 hiov[i].iov_len); 1185 } 1186 1187 int result = writev(process->sim_fd(fd), hiov, count); 1188 1189 for (size_t i = 0; i < count; ++i) 1190 delete [] (char *)hiov[i].iov_base; 1191 1192 if (result < 0) 1193 return -errno; 1194 1195 return 0; 1196} 1197 1198 1199/// Target mmap() handler. 1200/// 1201/// We don't really handle mmap(). If the target is mmaping an 1202/// anonymous region or /dev/zero, we can get away with doing basically 1203/// nothing (since memory is initialized to zero and the simulator 1204/// doesn't really check addresses anyway). 1205/// 1206template <class OS> 1207SyscallReturn 1208mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1209{ 1210 int index = 0; 1211 Addr start = p->getSyscallArg(tc, index); 1212 uint64_t length = p->getSyscallArg(tc, index); 1213 index++; // int prot = p->getSyscallArg(tc, index); 1214 int flags = p->getSyscallArg(tc, index); 1215 int tgt_fd = p->getSyscallArg(tc, index); 1216 // int offset = p->getSyscallArg(tc, index); 1217 1218 if (length > 0x100000000ULL) 1219 warn("mmap length argument %#x is unreasonably large.\n", length); 1220 1221 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1222 Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd); 1223 if (!fd_map || fd_map->fd < 0) { 1224 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1225 return -EBADF; 1226 } 1227 1228 if (fd_map->filename != "/dev/zero") { 1229 // This is very likely broken, but leave a warning here 1230 // (rather than panic) in case /dev/zero is known by 1231 // another name on some platform 1232 warn("allowing mmap of file %s; mmap not supported on files" 1233 " other than /dev/zero\n", fd_map->filename); 1234 } 1235 } 1236 1237 if ((start % TheISA::PageBytes) != 0 || 1238 (length % TheISA::PageBytes) != 0) { 1239 warn("mmap failing: arguments not page-aligned: " 1240 "start 0x%x length 0x%x", 1241 start, length); 1242 return -EINVAL; 1243 } 1244 1245 // are we ok with clobbering existing mappings? only set this to 1246 // true if the user has been warned. 1247 bool clobber = false; 1248 1249 // try to use the caller-provided address if there is one 1250 bool use_provided_address = (start != 0); 1251 1252 if (use_provided_address) { 1253 // check to see if the desired address is already in use 1254 if (!p->pTable->isUnmapped(start, length)) { 1255 // there are existing mappings in the desired range 1256 // whether we clobber them or not depends on whether the caller 1257 // specified MAP_FIXED 1258 if (flags & OS::TGT_MAP_FIXED) { 1259 // MAP_FIXED specified: clobber existing mappings 1260 warn("mmap: MAP_FIXED at 0x%x overwrites existing mappings\n", 1261 start); 1262 clobber = true; 1263 } else { 1264 // MAP_FIXED not specified: ignore suggested start address 1265 warn("mmap: ignoring suggested map address 0x%x\n", start); 1266 use_provided_address = false; 1267 } 1268 } 1269 } 1270 1271 if (!use_provided_address) { 1272 // no address provided, or provided address unusable: 1273 // pick next address from our "mmap region" 1274 if (OS::mmapGrowsDown()) { 1275 start = p->mmap_end - length; 1276 p->mmap_end = start; 1277 } else { 1278 start = p->mmap_end; 1279 p->mmap_end += length; 1280 } 1281 } 1282 1283 p->allocateMem(start, length, clobber); 1284 1285 return start; 1286} 1287 1288/// Target getrlimit() handler. 1289template <class OS> 1290SyscallReturn 1291getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1292 ThreadContext *tc) 1293{ 1294 int index = 0; 1295 unsigned resource = process->getSyscallArg(tc, index); 1296 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1297 1298 switch (resource) { 1299 case OS::TGT_RLIMIT_STACK: 1300 // max stack size in bytes: make up a number (8MB for now) 1301 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1302 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1303 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1304 break; 1305 1306 case OS::TGT_RLIMIT_DATA: 1307 // max data segment size in bytes: make up a number 1308 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1309 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1310 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1311 break; 1312 1313 default: 1314 std::cerr << "getrlimitFunc: unimplemented resource " << resource 1315 << std::endl; 1316 abort(); 1317 break; 1318 } 1319 1320 rlp.copyOut(tc->getMemProxy()); 1321 return 0; 1322} 1323 1324/// Target gettimeofday() handler. 1325template <class OS> 1326SyscallReturn 1327gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1328 ThreadContext *tc) 1329{ 1330 int index = 0; 1331 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1332 1333 getElapsedTime(tp->tv_sec, tp->tv_usec); 1334 tp->tv_sec += seconds_since_epoch; 1335 tp->tv_sec = TheISA::htog(tp->tv_sec); 1336 tp->tv_usec = TheISA::htog(tp->tv_usec); 1337 1338 tp.copyOut(tc->getMemProxy()); 1339 1340 return 0; 1341} 1342 1343 1344/// Target utimes() handler. 1345template <class OS> 1346SyscallReturn 1347utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1348 ThreadContext *tc) 1349{ 1350 std::string path; 1351 1352 int index = 0; 1353 if (!tc->getMemProxy().tryReadString(path, 1354 process->getSyscallArg(tc, index))) { 1355 return -EFAULT; 1356 } 1357 1358 TypedBufferArg<typename OS::timeval [2]> 1359 tp(process->getSyscallArg(tc, index)); 1360 tp.copyIn(tc->getMemProxy()); 1361 1362 struct timeval hostTimeval[2]; 1363 for (int i = 0; i < 2; ++i) 1364 { 1365 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1366 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1367 } 1368 1369 // Adjust path for current working directory 1370 path = process->fullPath(path); 1371 1372 int result = utimes(path.c_str(), hostTimeval); 1373 1374 if (result < 0) 1375 return -errno; 1376 1377 return 0; 1378} 1379/// Target getrusage() function. 1380template <class OS> 1381SyscallReturn 1382getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1383 ThreadContext *tc) 1384{ 1385 int index = 0; 1386 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1387 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1388 1389 rup->ru_utime.tv_sec = 0; 1390 rup->ru_utime.tv_usec = 0; 1391 rup->ru_stime.tv_sec = 0; 1392 rup->ru_stime.tv_usec = 0; 1393 rup->ru_maxrss = 0; 1394 rup->ru_ixrss = 0; 1395 rup->ru_idrss = 0; 1396 rup->ru_isrss = 0; 1397 rup->ru_minflt = 0; 1398 rup->ru_majflt = 0; 1399 rup->ru_nswap = 0; 1400 rup->ru_inblock = 0; 1401 rup->ru_oublock = 0; 1402 rup->ru_msgsnd = 0; 1403 rup->ru_msgrcv = 0; 1404 rup->ru_nsignals = 0; 1405 rup->ru_nvcsw = 0; 1406 rup->ru_nivcsw = 0; 1407 1408 switch (who) { 1409 case OS::TGT_RUSAGE_SELF: 1410 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1411 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1412 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1413 break; 1414 1415 case OS::TGT_RUSAGE_CHILDREN: 1416 // do nothing. We have no child processes, so they take no time. 1417 break; 1418 1419 default: 1420 // don't really handle THREAD or CHILDREN, but just warn and 1421 // plow ahead 1422 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1423 who); 1424 } 1425 1426 rup.copyOut(tc->getMemProxy()); 1427 1428 return 0; 1429} 1430 1431/// Target times() function. 1432template <class OS> 1433SyscallReturn 1434timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1435 ThreadContext *tc) 1436{ 1437 int index = 0; 1438 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1439 1440 // Fill in the time structure (in clocks) 1441 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1442 bufp->tms_utime = clocks; 1443 bufp->tms_stime = 0; 1444 bufp->tms_cutime = 0; 1445 bufp->tms_cstime = 0; 1446 1447 // Convert to host endianness 1448 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1449 1450 // Write back 1451 bufp.copyOut(tc->getMemProxy()); 1452 1453 // Return clock ticks since system boot 1454 return clocks; 1455} 1456 1457/// Target time() function. 1458template <class OS> 1459SyscallReturn 1460timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1461 ThreadContext *tc) 1462{ 1463 typename OS::time_t sec, usec; 1464 getElapsedTime(sec, usec); 1465 sec += seconds_since_epoch; 1466 1467 int index = 0; 1468 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1469 if(taddr != 0) { 1470 typename OS::time_t t = sec; 1471 t = TheISA::htog(t); 1472 SETranslatingPortProxy &p = tc->getMemProxy(); 1473 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1474 } 1475 return sec; 1476} 1477 1478 1479#endif // __SIM_SYSCALL_EMUL_HH__ 1480