syscall_emul.hh revision 10831
1/* 2 * Copyright (c) 2012-2013 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 fd = process->getSyscallArg(tc, index); 557 unsigned req = process->getSyscallArg(tc, index); 558 559 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 560 561 Process::FdMap *fdObj = process->sim_fd_obj(fd); 562 563 if (fdObj == NULL) { 564 // doesn't map to any simulator fd: not a valid target fd 565 return -EBADF; 566 } 567 568 if (fdObj->driver != NULL) { 569 return fdObj->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 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 sysinfo() handler. 719template <class OS> 720SyscallReturn 721sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 722 ThreadContext *tc) 723{ 724 725 int index = 0; 726 TypedBufferArg<typename OS::tgt_sysinfo> 727 sysinfo(process->getSyscallArg(tc, index)); 728 729 sysinfo->uptime=seconds_since_epoch; 730 sysinfo->totalram=process->system->memSize(); 731 732 sysinfo.copyOut(tc->getMemProxy()); 733 734 return 0; 735} 736 737/// Target chmod() handler. 738template <class OS> 739SyscallReturn 740chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 741 ThreadContext *tc) 742{ 743 std::string path; 744 745 int index = 0; 746 if (!tc->getMemProxy().tryReadString(path, 747 process->getSyscallArg(tc, index))) { 748 return -EFAULT; 749 } 750 751 uint32_t mode = process->getSyscallArg(tc, index); 752 mode_t hostMode = 0; 753 754 // XXX translate mode flags via OS::something??? 755 hostMode = mode; 756 757 // Adjust path for current working directory 758 path = process->fullPath(path); 759 760 // do the chmod 761 int result = chmod(path.c_str(), hostMode); 762 if (result < 0) 763 return -errno; 764 765 return 0; 766} 767 768 769/// Target fchmod() handler. 770template <class OS> 771SyscallReturn 772fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 773 ThreadContext *tc) 774{ 775 int index = 0; 776 int fd = process->getSyscallArg(tc, index); 777 if (fd < 0 || process->sim_fd(fd) < 0) { 778 // doesn't map to any simulator fd: not a valid target fd 779 return -EBADF; 780 } 781 782 uint32_t mode = process->getSyscallArg(tc, index); 783 mode_t hostMode = 0; 784 785 // XXX translate mode flags via OS::someting??? 786 hostMode = mode; 787 788 // do the fchmod 789 int result = fchmod(process->sim_fd(fd), hostMode); 790 if (result < 0) 791 return -errno; 792 793 return 0; 794} 795 796/// Target mremap() handler. 797template <class OS> 798SyscallReturn 799mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 800{ 801 int index = 0; 802 Addr start = process->getSyscallArg(tc, index); 803 uint64_t old_length = process->getSyscallArg(tc, index); 804 uint64_t new_length = process->getSyscallArg(tc, index); 805 uint64_t flags = process->getSyscallArg(tc, index); 806 uint64_t provided_address = 0; 807 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 808 809 if (use_provided_address) 810 provided_address = process->getSyscallArg(tc, index); 811 812 if ((start % TheISA::PageBytes != 0) || 813 (provided_address % TheISA::PageBytes != 0)) { 814 warn("mremap failing: arguments not page aligned"); 815 return -EINVAL; 816 } 817 818 new_length = roundUp(new_length, TheISA::PageBytes); 819 820 if (new_length > old_length) { 821 if ((start + old_length) == process->mmap_end && 822 (!use_provided_address || provided_address == start)) { 823 uint64_t diff = new_length - old_length; 824 process->allocateMem(process->mmap_end, diff); 825 process->mmap_end += diff; 826 return start; 827 } else { 828 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 829 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 830 return -ENOMEM; 831 } else { 832 uint64_t new_start = use_provided_address ? 833 provided_address : process->mmap_end; 834 process->pTable->remap(start, old_length, new_start); 835 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 836 new_start, new_start + new_length, 837 new_length - old_length); 838 // add on the remaining unallocated pages 839 process->allocateMem(new_start + old_length, 840 new_length - old_length, 841 use_provided_address /* clobber */); 842 if (!use_provided_address) 843 process->mmap_end += new_length; 844 if (use_provided_address && 845 new_start + new_length > process->mmap_end) { 846 // something fishy going on here, at least notify the user 847 // @todo: increase mmap_end? 848 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 849 } 850 warn("returning %08p as start\n", new_start); 851 return new_start; 852 } 853 } 854 } else { 855 if (use_provided_address && provided_address != start) 856 process->pTable->remap(start, new_length, provided_address); 857 process->pTable->unmap(start + new_length, old_length - new_length); 858 return use_provided_address ? provided_address : start; 859 } 860} 861 862/// Target stat() handler. 863template <class OS> 864SyscallReturn 865statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 866 ThreadContext *tc) 867{ 868 std::string path; 869 870 int index = 0; 871 if (!tc->getMemProxy().tryReadString(path, 872 process->getSyscallArg(tc, index))) { 873 return -EFAULT; 874 } 875 Addr bufPtr = process->getSyscallArg(tc, index); 876 877 // Adjust path for current working directory 878 path = process->fullPath(path); 879 880 struct stat hostBuf; 881 int result = stat(path.c_str(), &hostBuf); 882 883 if (result < 0) 884 return -errno; 885 886 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 887 888 return 0; 889} 890 891 892/// Target stat64() handler. 893template <class OS> 894SyscallReturn 895stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 896 ThreadContext *tc) 897{ 898 std::string path; 899 900 int index = 0; 901 if (!tc->getMemProxy().tryReadString(path, 902 process->getSyscallArg(tc, index))) 903 return -EFAULT; 904 Addr bufPtr = process->getSyscallArg(tc, index); 905 906 // Adjust path for current working directory 907 path = process->fullPath(path); 908 909#if NO_STAT64 910 struct stat hostBuf; 911 int result = stat(path.c_str(), &hostBuf); 912#else 913 struct stat64 hostBuf; 914 int result = stat64(path.c_str(), &hostBuf); 915#endif 916 917 if (result < 0) 918 return -errno; 919 920 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 921 922 return 0; 923} 924 925 926/// Target fstatat64() handler. 927template <class OS> 928SyscallReturn 929fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 930 ThreadContext *tc) 931{ 932 int index = 0; 933 int dirfd = process->getSyscallArg(tc, index); 934 if (dirfd != OS::TGT_AT_FDCWD) 935 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 936 937 std::string path; 938 if (!tc->getMemProxy().tryReadString(path, 939 process->getSyscallArg(tc, index))) 940 return -EFAULT; 941 Addr bufPtr = process->getSyscallArg(tc, index); 942 943 // Adjust path for current working directory 944 path = process->fullPath(path); 945 946#if NO_STAT64 947 struct stat hostBuf; 948 int result = stat(path.c_str(), &hostBuf); 949#else 950 struct stat64 hostBuf; 951 int result = stat64(path.c_str(), &hostBuf); 952#endif 953 954 if (result < 0) 955 return -errno; 956 957 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 958 959 return 0; 960} 961 962 963/// Target fstat64() handler. 964template <class OS> 965SyscallReturn 966fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 967 ThreadContext *tc) 968{ 969 int index = 0; 970 int fd = process->getSyscallArg(tc, index); 971 Addr bufPtr = process->getSyscallArg(tc, index); 972 if (fd < 0 || process->sim_fd(fd) < 0) { 973 // doesn't map to any simulator fd: not a valid target fd 974 return -EBADF; 975 } 976 977#if NO_STAT64 978 struct stat hostBuf; 979 int result = fstat(process->sim_fd(fd), &hostBuf); 980#else 981 struct stat64 hostBuf; 982 int result = fstat64(process->sim_fd(fd), &hostBuf); 983#endif 984 985 if (result < 0) 986 return -errno; 987 988 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 989 990 return 0; 991} 992 993 994/// Target lstat() handler. 995template <class OS> 996SyscallReturn 997lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 998 ThreadContext *tc) 999{ 1000 std::string path; 1001 1002 int index = 0; 1003 if (!tc->getMemProxy().tryReadString(path, 1004 process->getSyscallArg(tc, index))) { 1005 return -EFAULT; 1006 } 1007 Addr bufPtr = process->getSyscallArg(tc, index); 1008 1009 // Adjust path for current working directory 1010 path = process->fullPath(path); 1011 1012 struct stat hostBuf; 1013 int result = lstat(path.c_str(), &hostBuf); 1014 1015 if (result < 0) 1016 return -errno; 1017 1018 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1019 1020 return 0; 1021} 1022 1023/// Target lstat64() handler. 1024template <class OS> 1025SyscallReturn 1026lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1027 ThreadContext *tc) 1028{ 1029 std::string path; 1030 1031 int index = 0; 1032 if (!tc->getMemProxy().tryReadString(path, 1033 process->getSyscallArg(tc, index))) { 1034 return -EFAULT; 1035 } 1036 Addr bufPtr = process->getSyscallArg(tc, index); 1037 1038 // Adjust path for current working directory 1039 path = process->fullPath(path); 1040 1041#if NO_STAT64 1042 struct stat hostBuf; 1043 int result = lstat(path.c_str(), &hostBuf); 1044#else 1045 struct stat64 hostBuf; 1046 int result = lstat64(path.c_str(), &hostBuf); 1047#endif 1048 1049 if (result < 0) 1050 return -errno; 1051 1052 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1053 1054 return 0; 1055} 1056 1057/// Target fstat() handler. 1058template <class OS> 1059SyscallReturn 1060fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1061 ThreadContext *tc) 1062{ 1063 int index = 0; 1064 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1065 Addr bufPtr = process->getSyscallArg(tc, index); 1066 1067 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 1068 1069 if (fd < 0) 1070 return -EBADF; 1071 1072 struct stat hostBuf; 1073 int result = fstat(fd, &hostBuf); 1074 1075 if (result < 0) 1076 return -errno; 1077 1078 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 1079 1080 return 0; 1081} 1082 1083 1084/// Target statfs() handler. 1085template <class OS> 1086SyscallReturn 1087statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1088 ThreadContext *tc) 1089{ 1090 std::string path; 1091 1092 int index = 0; 1093 if (!tc->getMemProxy().tryReadString(path, 1094 process->getSyscallArg(tc, index))) { 1095 return -EFAULT; 1096 } 1097 Addr bufPtr = process->getSyscallArg(tc, index); 1098 1099 // Adjust path for current working directory 1100 path = process->fullPath(path); 1101 1102 struct statfs hostBuf; 1103 int result = statfs(path.c_str(), &hostBuf); 1104 1105 if (result < 0) 1106 return -errno; 1107 1108 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1109 1110 return 0; 1111} 1112 1113 1114/// Target fstatfs() handler. 1115template <class OS> 1116SyscallReturn 1117fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1118 ThreadContext *tc) 1119{ 1120 int index = 0; 1121 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1122 Addr bufPtr = process->getSyscallArg(tc, index); 1123 1124 if (fd < 0) 1125 return -EBADF; 1126 1127 struct statfs hostBuf; 1128 int result = fstatfs(fd, &hostBuf); 1129 1130 if (result < 0) 1131 return -errno; 1132 1133 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1134 1135 return 0; 1136} 1137 1138 1139/// Target writev() handler. 1140template <class OS> 1141SyscallReturn 1142writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1143 ThreadContext *tc) 1144{ 1145 int index = 0; 1146 int fd = process->getSyscallArg(tc, index); 1147 if (fd < 0 || process->sim_fd(fd) < 0) { 1148 // doesn't map to any simulator fd: not a valid target fd 1149 return -EBADF; 1150 } 1151 1152 SETranslatingPortProxy &p = tc->getMemProxy(); 1153 uint64_t tiov_base = process->getSyscallArg(tc, index); 1154 size_t count = process->getSyscallArg(tc, index); 1155 struct iovec hiov[count]; 1156 for (size_t i = 0; i < count; ++i) { 1157 typename OS::tgt_iovec tiov; 1158 1159 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1160 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1161 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1162 hiov[i].iov_base = new char [hiov[i].iov_len]; 1163 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1164 hiov[i].iov_len); 1165 } 1166 1167 int result = writev(process->sim_fd(fd), hiov, count); 1168 1169 for (size_t i = 0; i < count; ++i) 1170 delete [] (char *)hiov[i].iov_base; 1171 1172 if (result < 0) 1173 return -errno; 1174 1175 return result; 1176} 1177 1178 1179/// Target mmap() handler. 1180/// 1181/// We don't really handle mmap(). If the target is mmaping an 1182/// anonymous region or /dev/zero, we can get away with doing basically 1183/// nothing (since memory is initialized to zero and the simulator 1184/// doesn't really check addresses anyway). 1185/// 1186template <class OS> 1187SyscallReturn 1188mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1189{ 1190 int index = 0; 1191 Addr start = p->getSyscallArg(tc, index); 1192 uint64_t length = p->getSyscallArg(tc, index); 1193 index++; // int prot = p->getSyscallArg(tc, index); 1194 int flags = p->getSyscallArg(tc, index); 1195 int tgt_fd = p->getSyscallArg(tc, index); 1196 int offset = p->getSyscallArg(tc, index); 1197 1198 if (length > 0x100000000ULL) 1199 warn("mmap length argument %#x is unreasonably large.\n", length); 1200 1201 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1202 Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd); 1203 if (!fd_map || fd_map->fd < 0) { 1204 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1205 return -EBADF; 1206 } 1207 1208 if (fd_map->filename != "/dev/zero") { 1209 // This is very likely broken, but leave a warning here 1210 // (rather than panic) in case /dev/zero is known by 1211 // another name on some platform 1212 warn("allowing mmap of file %s; mmap not supported on files" 1213 " other than /dev/zero\n", fd_map->filename); 1214 } 1215 } 1216 1217 length = roundUp(length, TheISA::PageBytes); 1218 1219 if ((start % TheISA::PageBytes) != 0 || 1220 (offset % TheISA::PageBytes) != 0) { 1221 warn("mmap failing: arguments not page-aligned: " 1222 "start 0x%x offset 0x%x", 1223 start, offset); 1224 return -EINVAL; 1225 } 1226 1227 // are we ok with clobbering existing mappings? only set this to 1228 // true if the user has been warned. 1229 bool clobber = false; 1230 1231 // try to use the caller-provided address if there is one 1232 bool use_provided_address = (start != 0); 1233 1234 if (use_provided_address) { 1235 // check to see if the desired address is already in use 1236 if (!p->pTable->isUnmapped(start, length)) { 1237 // there are existing mappings in the desired range 1238 // whether we clobber them or not depends on whether the caller 1239 // specified MAP_FIXED 1240 if (flags & OS::TGT_MAP_FIXED) { 1241 // MAP_FIXED specified: map attempt fails 1242 return -EINVAL; 1243 } else { 1244 // MAP_FIXED not specified: ignore suggested start address 1245 warn("mmap: ignoring suggested map address 0x%x\n", start); 1246 use_provided_address = false; 1247 } 1248 } 1249 } 1250 1251 if (!use_provided_address) { 1252 // no address provided, or provided address unusable: 1253 // pick next address from our "mmap region" 1254 if (OS::mmapGrowsDown()) { 1255 start = p->mmap_end - length; 1256 p->mmap_end = start; 1257 } else { 1258 start = p->mmap_end; 1259 p->mmap_end += length; 1260 } 1261 } 1262 1263 p->allocateMem(start, length, clobber); 1264 1265 return start; 1266} 1267 1268/// Target getrlimit() handler. 1269template <class OS> 1270SyscallReturn 1271getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1272 ThreadContext *tc) 1273{ 1274 int index = 0; 1275 unsigned resource = process->getSyscallArg(tc, index); 1276 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1277 1278 switch (resource) { 1279 case OS::TGT_RLIMIT_STACK: 1280 // max stack size in bytes: make up a number (8MB for now) 1281 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1282 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1283 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1284 break; 1285 1286 case OS::TGT_RLIMIT_DATA: 1287 // max data segment size in bytes: make up a number 1288 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1289 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1290 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1291 break; 1292 1293 default: 1294 warn("getrlimit: unimplemented resource %d", resource); 1295 return -EINVAL; 1296 break; 1297 } 1298 1299 rlp.copyOut(tc->getMemProxy()); 1300 return 0; 1301} 1302 1303/// Target clock_gettime() function. 1304template <class OS> 1305SyscallReturn 1306clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1307{ 1308 int index = 1; 1309 //int clk_id = p->getSyscallArg(tc, index); 1310 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1311 1312 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1313 tp->tv_sec += seconds_since_epoch; 1314 tp->tv_sec = TheISA::htog(tp->tv_sec); 1315 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1316 1317 tp.copyOut(tc->getMemProxy()); 1318 1319 return 0; 1320} 1321 1322/// Target gettimeofday() handler. 1323template <class OS> 1324SyscallReturn 1325gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1326 ThreadContext *tc) 1327{ 1328 int index = 0; 1329 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1330 1331 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1332 tp->tv_sec += seconds_since_epoch; 1333 tp->tv_sec = TheISA::htog(tp->tv_sec); 1334 tp->tv_usec = TheISA::htog(tp->tv_usec); 1335 1336 tp.copyOut(tc->getMemProxy()); 1337 1338 return 0; 1339} 1340 1341 1342/// Target utimes() handler. 1343template <class OS> 1344SyscallReturn 1345utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1346 ThreadContext *tc) 1347{ 1348 std::string path; 1349 1350 int index = 0; 1351 if (!tc->getMemProxy().tryReadString(path, 1352 process->getSyscallArg(tc, index))) { 1353 return -EFAULT; 1354 } 1355 1356 TypedBufferArg<typename OS::timeval [2]> 1357 tp(process->getSyscallArg(tc, index)); 1358 tp.copyIn(tc->getMemProxy()); 1359 1360 struct timeval hostTimeval[2]; 1361 for (int i = 0; i < 2; ++i) 1362 { 1363 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1364 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1365 } 1366 1367 // Adjust path for current working directory 1368 path = process->fullPath(path); 1369 1370 int result = utimes(path.c_str(), hostTimeval); 1371 1372 if (result < 0) 1373 return -errno; 1374 1375 return 0; 1376} 1377/// Target getrusage() function. 1378template <class OS> 1379SyscallReturn 1380getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1381 ThreadContext *tc) 1382{ 1383 int index = 0; 1384 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1385 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1386 1387 rup->ru_utime.tv_sec = 0; 1388 rup->ru_utime.tv_usec = 0; 1389 rup->ru_stime.tv_sec = 0; 1390 rup->ru_stime.tv_usec = 0; 1391 rup->ru_maxrss = 0; 1392 rup->ru_ixrss = 0; 1393 rup->ru_idrss = 0; 1394 rup->ru_isrss = 0; 1395 rup->ru_minflt = 0; 1396 rup->ru_majflt = 0; 1397 rup->ru_nswap = 0; 1398 rup->ru_inblock = 0; 1399 rup->ru_oublock = 0; 1400 rup->ru_msgsnd = 0; 1401 rup->ru_msgrcv = 0; 1402 rup->ru_nsignals = 0; 1403 rup->ru_nvcsw = 0; 1404 rup->ru_nivcsw = 0; 1405 1406 switch (who) { 1407 case OS::TGT_RUSAGE_SELF: 1408 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1409 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1410 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1411 break; 1412 1413 case OS::TGT_RUSAGE_CHILDREN: 1414 // do nothing. We have no child processes, so they take no time. 1415 break; 1416 1417 default: 1418 // don't really handle THREAD or CHILDREN, but just warn and 1419 // plow ahead 1420 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1421 who); 1422 } 1423 1424 rup.copyOut(tc->getMemProxy()); 1425 1426 return 0; 1427} 1428 1429/// Target times() function. 1430template <class OS> 1431SyscallReturn 1432timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1433 ThreadContext *tc) 1434{ 1435 int index = 0; 1436 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1437 1438 // Fill in the time structure (in clocks) 1439 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1440 bufp->tms_utime = clocks; 1441 bufp->tms_stime = 0; 1442 bufp->tms_cutime = 0; 1443 bufp->tms_cstime = 0; 1444 1445 // Convert to host endianness 1446 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1447 1448 // Write back 1449 bufp.copyOut(tc->getMemProxy()); 1450 1451 // Return clock ticks since system boot 1452 return clocks; 1453} 1454 1455/// Target time() function. 1456template <class OS> 1457SyscallReturn 1458timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1459 ThreadContext *tc) 1460{ 1461 typename OS::time_t sec, usec; 1462 getElapsedTimeMicro(sec, usec); 1463 sec += seconds_since_epoch; 1464 1465 int index = 0; 1466 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1467 if(taddr != 0) { 1468 typename OS::time_t t = sec; 1469 t = TheISA::htog(t); 1470 SETranslatingPortProxy &p = tc->getMemProxy(); 1471 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1472 } 1473 return sec; 1474} 1475 1476 1477#endif // __SIM_SYSCALL_EMUL_HH__ 1478