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