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