syscall_emul.hh revision 10930
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->get_fd_entry(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->alloc_fd(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 fd = process->getSyscallArg(tc, index); 813 if (fd < 0 || process->sim_fd(fd) < 0) { 814 // doesn't map to any simulator fd: not a valid target fd 815 return -EBADF; 816 } 817 818 uint32_t mode = process->getSyscallArg(tc, index); 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(process->sim_fd(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 fd = process->getSyscallArg(tc, index); 1007 Addr bufPtr = process->getSyscallArg(tc, index); 1008 if (fd < 0 || process->sim_fd(fd) < 0) { 1009 // doesn't map to any simulator fd: not a valid target fd 1010 return -EBADF; 1011 } 1012 1013#if NO_STAT64 1014 struct stat hostBuf; 1015 int result = fstat(process->sim_fd(fd), &hostBuf); 1016#else 1017 struct stat64 hostBuf; 1018 int result = fstat64(process->sim_fd(fd), &hostBuf); 1019#endif 1020 1021 if (result < 0) 1022 return -errno; 1023 1024 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (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 fd = process->sim_fd(process->getSyscallArg(tc, index)); 1101 Addr bufPtr = process->getSyscallArg(tc, index); 1102 1103 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 1104 1105 if (fd < 0) 1106 return -EBADF; 1107 1108 struct stat hostBuf; 1109 int result = fstat(fd, &hostBuf); 1110 1111 if (result < 0) 1112 return -errno; 1113 1114 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 1115 1116 return 0; 1117} 1118 1119 1120/// Target statfs() handler. 1121template <class OS> 1122SyscallReturn 1123statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1124 ThreadContext *tc) 1125{ 1126 std::string path; 1127 1128 int index = 0; 1129 if (!tc->getMemProxy().tryReadString(path, 1130 process->getSyscallArg(tc, index))) { 1131 return -EFAULT; 1132 } 1133 Addr bufPtr = process->getSyscallArg(tc, index); 1134 1135 // Adjust path for current working directory 1136 path = process->fullPath(path); 1137 1138 struct statfs hostBuf; 1139 int result = statfs(path.c_str(), &hostBuf); 1140 1141 if (result < 0) 1142 return -errno; 1143 1144 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1145 1146 return 0; 1147} 1148 1149 1150/// Target fstatfs() handler. 1151template <class OS> 1152SyscallReturn 1153fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1154 ThreadContext *tc) 1155{ 1156 int index = 0; 1157 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1158 Addr bufPtr = process->getSyscallArg(tc, index); 1159 1160 if (fd < 0) 1161 return -EBADF; 1162 1163 struct statfs hostBuf; 1164 int result = fstatfs(fd, &hostBuf); 1165 1166 if (result < 0) 1167 return -errno; 1168 1169 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1170 1171 return 0; 1172} 1173 1174 1175/// Target writev() handler. 1176template <class OS> 1177SyscallReturn 1178writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1179 ThreadContext *tc) 1180{ 1181 int index = 0; 1182 int fd = process->getSyscallArg(tc, index); 1183 if (fd < 0 || process->sim_fd(fd) < 0) { 1184 // doesn't map to any simulator fd: not a valid target fd 1185 return -EBADF; 1186 } 1187 1188 SETranslatingPortProxy &p = tc->getMemProxy(); 1189 uint64_t tiov_base = process->getSyscallArg(tc, index); 1190 size_t count = process->getSyscallArg(tc, index); 1191 struct iovec hiov[count]; 1192 for (size_t i = 0; i < count; ++i) { 1193 typename OS::tgt_iovec tiov; 1194 1195 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1196 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1197 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1198 hiov[i].iov_base = new char [hiov[i].iov_len]; 1199 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1200 hiov[i].iov_len); 1201 } 1202 1203 int result = writev(process->sim_fd(fd), hiov, count); 1204 1205 for (size_t i = 0; i < count; ++i) 1206 delete [] (char *)hiov[i].iov_base; 1207 1208 if (result < 0) 1209 return -errno; 1210 1211 return result; 1212} 1213 1214 1215/// Target mmap() handler. 1216/// 1217/// We don't really handle mmap(). If the target is mmaping an 1218/// anonymous region or /dev/zero, we can get away with doing basically 1219/// nothing (since memory is initialized to zero and the simulator 1220/// doesn't really check addresses anyway). 1221/// 1222template <class OS> 1223SyscallReturn 1224mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1225{ 1226 int index = 0; 1227 Addr start = p->getSyscallArg(tc, index); 1228 uint64_t length = p->getSyscallArg(tc, index); 1229 index++; // int prot = p->getSyscallArg(tc, index); 1230 int flags = p->getSyscallArg(tc, index); 1231 int tgt_fd = p->getSyscallArg(tc, index); 1232 int offset = p->getSyscallArg(tc, index); 1233 1234 if (length > 0x100000000ULL) 1235 warn("mmap length argument %#x is unreasonably large.\n", length); 1236 1237 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1238 FDEntry *fde = p->get_fd_entry(tgt_fd); 1239 if (!fde || fde->fd < 0) { 1240 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1241 return -EBADF; 1242 } 1243 1244 if (fde->filename != "/dev/zero") { 1245 // This is very likely broken, but leave a warning here 1246 // (rather than panic) in case /dev/zero is known by 1247 // another name on some platform 1248 warn("allowing mmap of file %s; mmap not supported on files" 1249 " other than /dev/zero\n", fde->filename); 1250 } 1251 } 1252 1253 length = roundUp(length, TheISA::PageBytes); 1254 1255 if ((start % TheISA::PageBytes) != 0 || 1256 (offset % TheISA::PageBytes) != 0) { 1257 warn("mmap failing: arguments not page-aligned: " 1258 "start 0x%x offset 0x%x", 1259 start, offset); 1260 return -EINVAL; 1261 } 1262 1263 // are we ok with clobbering existing mappings? only set this to 1264 // true if the user has been warned. 1265 bool clobber = false; 1266 1267 // try to use the caller-provided address if there is one 1268 bool use_provided_address = (start != 0); 1269 1270 if (use_provided_address) { 1271 // check to see if the desired address is already in use 1272 if (!p->pTable->isUnmapped(start, length)) { 1273 // there are existing mappings in the desired range 1274 // whether we clobber them or not depends on whether the caller 1275 // specified MAP_FIXED 1276 if (flags & OS::TGT_MAP_FIXED) { 1277 // MAP_FIXED specified: map attempt fails 1278 return -EINVAL; 1279 } else { 1280 // MAP_FIXED not specified: ignore suggested start address 1281 warn("mmap: ignoring suggested map address 0x%x\n", start); 1282 use_provided_address = false; 1283 } 1284 } 1285 } 1286 1287 if (!use_provided_address) { 1288 // no address provided, or provided address unusable: 1289 // pick next address from our "mmap region" 1290 if (OS::mmapGrowsDown()) { 1291 start = p->mmap_end - length; 1292 p->mmap_end = start; 1293 } else { 1294 start = p->mmap_end; 1295 p->mmap_end += length; 1296 } 1297 } 1298 1299 p->allocateMem(start, length, clobber); 1300 1301 return start; 1302} 1303 1304/// Target getrlimit() handler. 1305template <class OS> 1306SyscallReturn 1307getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1308 ThreadContext *tc) 1309{ 1310 int index = 0; 1311 unsigned resource = process->getSyscallArg(tc, index); 1312 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1313 1314 switch (resource) { 1315 case OS::TGT_RLIMIT_STACK: 1316 // max stack size in bytes: make up a number (8MB for now) 1317 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1318 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1319 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1320 break; 1321 1322 case OS::TGT_RLIMIT_DATA: 1323 // max data segment size in bytes: make up a number 1324 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1325 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1326 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1327 break; 1328 1329 default: 1330 warn("getrlimit: unimplemented resource %d", resource); 1331 return -EINVAL; 1332 break; 1333 } 1334 1335 rlp.copyOut(tc->getMemProxy()); 1336 return 0; 1337} 1338 1339/// Target clock_gettime() function. 1340template <class OS> 1341SyscallReturn 1342clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1343{ 1344 int index = 1; 1345 //int clk_id = p->getSyscallArg(tc, index); 1346 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1347 1348 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1349 tp->tv_sec += seconds_since_epoch; 1350 tp->tv_sec = TheISA::htog(tp->tv_sec); 1351 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1352 1353 tp.copyOut(tc->getMemProxy()); 1354 1355 return 0; 1356} 1357 1358/// Target gettimeofday() handler. 1359template <class OS> 1360SyscallReturn 1361gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1362 ThreadContext *tc) 1363{ 1364 int index = 0; 1365 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1366 1367 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1368 tp->tv_sec += seconds_since_epoch; 1369 tp->tv_sec = TheISA::htog(tp->tv_sec); 1370 tp->tv_usec = TheISA::htog(tp->tv_usec); 1371 1372 tp.copyOut(tc->getMemProxy()); 1373 1374 return 0; 1375} 1376 1377 1378/// Target utimes() handler. 1379template <class OS> 1380SyscallReturn 1381utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1382 ThreadContext *tc) 1383{ 1384 std::string path; 1385 1386 int index = 0; 1387 if (!tc->getMemProxy().tryReadString(path, 1388 process->getSyscallArg(tc, index))) { 1389 return -EFAULT; 1390 } 1391 1392 TypedBufferArg<typename OS::timeval [2]> 1393 tp(process->getSyscallArg(tc, index)); 1394 tp.copyIn(tc->getMemProxy()); 1395 1396 struct timeval hostTimeval[2]; 1397 for (int i = 0; i < 2; ++i) 1398 { 1399 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1400 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1401 } 1402 1403 // Adjust path for current working directory 1404 path = process->fullPath(path); 1405 1406 int result = utimes(path.c_str(), hostTimeval); 1407 1408 if (result < 0) 1409 return -errno; 1410 1411 return 0; 1412} 1413/// Target getrusage() function. 1414template <class OS> 1415SyscallReturn 1416getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1417 ThreadContext *tc) 1418{ 1419 int index = 0; 1420 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1421 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1422 1423 rup->ru_utime.tv_sec = 0; 1424 rup->ru_utime.tv_usec = 0; 1425 rup->ru_stime.tv_sec = 0; 1426 rup->ru_stime.tv_usec = 0; 1427 rup->ru_maxrss = 0; 1428 rup->ru_ixrss = 0; 1429 rup->ru_idrss = 0; 1430 rup->ru_isrss = 0; 1431 rup->ru_minflt = 0; 1432 rup->ru_majflt = 0; 1433 rup->ru_nswap = 0; 1434 rup->ru_inblock = 0; 1435 rup->ru_oublock = 0; 1436 rup->ru_msgsnd = 0; 1437 rup->ru_msgrcv = 0; 1438 rup->ru_nsignals = 0; 1439 rup->ru_nvcsw = 0; 1440 rup->ru_nivcsw = 0; 1441 1442 switch (who) { 1443 case OS::TGT_RUSAGE_SELF: 1444 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1445 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1446 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1447 break; 1448 1449 case OS::TGT_RUSAGE_CHILDREN: 1450 // do nothing. We have no child processes, so they take no time. 1451 break; 1452 1453 default: 1454 // don't really handle THREAD or CHILDREN, but just warn and 1455 // plow ahead 1456 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1457 who); 1458 } 1459 1460 rup.copyOut(tc->getMemProxy()); 1461 1462 return 0; 1463} 1464 1465/// Target times() function. 1466template <class OS> 1467SyscallReturn 1468timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1469 ThreadContext *tc) 1470{ 1471 int index = 0; 1472 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1473 1474 // Fill in the time structure (in clocks) 1475 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1476 bufp->tms_utime = clocks; 1477 bufp->tms_stime = 0; 1478 bufp->tms_cutime = 0; 1479 bufp->tms_cstime = 0; 1480 1481 // Convert to host endianness 1482 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1483 1484 // Write back 1485 bufp.copyOut(tc->getMemProxy()); 1486 1487 // Return clock ticks since system boot 1488 return clocks; 1489} 1490 1491/// Target time() function. 1492template <class OS> 1493SyscallReturn 1494timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1495 ThreadContext *tc) 1496{ 1497 typename OS::time_t sec, usec; 1498 getElapsedTimeMicro(sec, usec); 1499 sec += seconds_since_epoch; 1500 1501 int index = 0; 1502 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1503 if(taddr != 0) { 1504 typename OS::time_t t = sec; 1505 t = TheISA::htog(t); 1506 SETranslatingPortProxy &p = tc->getMemProxy(); 1507 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1508 } 1509 return sec; 1510} 1511 1512 1513#endif // __SIM_SYSCALL_EMUL_HH__ 1514