syscall_emul.hh revision 2687
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Kevin Lim 30 */ 31 32#ifndef __SIM_SYSCALL_EMUL_HH__ 33#define __SIM_SYSCALL_EMUL_HH__ 34 35#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ 36 defined(__FreeBSD__)) 37 38/// 39/// @file syscall_emul.hh 40/// 41/// This file defines objects used to emulate syscalls from the target 42/// application on the host machine. 43 44#include <errno.h> 45#include <string> 46#ifdef __CYGWIN32__ 47#include <sys/fcntl.h> // for O_BINARY 48#endif 49#include <sys/uio.h> 50 51#include "arch/isa_traits.hh" // for Addr 52#include "base/chunk_generator.hh" 53#include "base/intmath.hh" // for RoundUp 54#include "base/misc.hh" 55#include "base/trace.hh" 56#include "cpu/base.hh" 57#include "cpu/thread_context.hh" 58#include "mem/translating_port.hh" 59#include "mem/page_table.hh" 60#include "sim/process.hh" 61 62/// 63/// System call descriptor. 64/// 65class SyscallDesc { 66 67 public: 68 69 /// Typedef for target syscall handler functions. 70 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 71 Process *, ThreadContext *); 72 73 const char *name; //!< Syscall name (e.g., "open"). 74 FuncPtr funcPtr; //!< Pointer to emulation function. 75 int flags; //!< Flags (see Flags enum). 76 77 /// Flag values for controlling syscall behavior. 78 enum Flags { 79 /// Don't set return regs according to funcPtr return value. 80 /// Used for syscalls with non-standard return conventions 81 /// that explicitly set the ThreadContext regs (e.g., 82 /// sigreturn). 83 SuppressReturnValue = 1 84 }; 85 86 /// Constructor. 87 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 88 : name(_name), funcPtr(_funcPtr), flags(_flags) 89 { 90 } 91 92 /// Emulate the syscall. Public interface for calling through funcPtr. 93 void doSyscall(int callnum, Process *proc, ThreadContext *tc); 94}; 95 96 97class BaseBufferArg { 98 99 public: 100 101 BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 102 { 103 bufPtr = new uint8_t[size]; 104 // clear out buffer: in case we only partially populate this, 105 // and then do a copyOut(), we want to make sure we don't 106 // introduce any random junk into the simulated address space 107 memset(bufPtr, 0, size); 108 } 109 110 virtual ~BaseBufferArg() { delete [] bufPtr; } 111 112 // 113 // copy data into simulator space (read from target memory) 114 // 115 virtual bool copyIn(TranslatingPort *memport) 116 { 117 memport->readBlob(addr, bufPtr, size); 118 return true; // no EFAULT detection for now 119 } 120 121 // 122 // copy data out of simulator space (write to target memory) 123 // 124 virtual bool copyOut(TranslatingPort *memport) 125 { 126 memport->writeBlob(addr, bufPtr, size); 127 return true; // no EFAULT detection for now 128 } 129 130 protected: 131 Addr addr; 132 int size; 133 uint8_t *bufPtr; 134}; 135 136 137class BufferArg : public BaseBufferArg 138{ 139 public: 140 BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 141 void *bufferPtr() { return bufPtr; } 142}; 143 144template <class T> 145class TypedBufferArg : public BaseBufferArg 146{ 147 public: 148 // user can optionally specify a specific number of bytes to 149 // allocate to deal with those structs that have variable-size 150 // arrays at the end 151 TypedBufferArg(Addr _addr, int _size = sizeof(T)) 152 : BaseBufferArg(_addr, _size) 153 { } 154 155 // type case 156 operator T*() { return (T *)bufPtr; } 157 158 // dereference operators 159 T &operator*() { return *((T *)bufPtr); } 160 T* operator->() { return (T *)bufPtr; } 161 T &operator[](int i) { return ((T *)bufPtr)[i]; } 162}; 163 164////////////////////////////////////////////////////////////////////// 165// 166// The following emulation functions are generic enough that they 167// don't need to be recompiled for different emulated OS's. They are 168// defined in sim/syscall_emul.cc. 169// 170////////////////////////////////////////////////////////////////////// 171 172 173/// Handler for unimplemented syscalls that we haven't thought about. 174SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 175 Process *p, ThreadContext *tc); 176 177/// Handler for unimplemented syscalls that we never intend to 178/// implement (signal handling, etc.) and should not affect the correct 179/// behavior of the program. Print a warning only if the appropriate 180/// trace flag is enabled. Return success to the target program. 181SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 182 Process *p, ThreadContext *tc); 183 184/// Target exit() handler: terminate simulation. 185SyscallReturn exitFunc(SyscallDesc *desc, int num, 186 Process *p, ThreadContext *tc); 187 188/// Target getpagesize() handler. 189SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 190 Process *p, ThreadContext *tc); 191 192/// Target obreak() handler: set brk address. 193SyscallReturn obreakFunc(SyscallDesc *desc, int num, 194 Process *p, ThreadContext *tc); 195 196/// Target close() handler. 197SyscallReturn closeFunc(SyscallDesc *desc, int num, 198 Process *p, ThreadContext *tc); 199 200/// Target read() handler. 201SyscallReturn readFunc(SyscallDesc *desc, int num, 202 Process *p, ThreadContext *tc); 203 204/// Target write() handler. 205SyscallReturn writeFunc(SyscallDesc *desc, int num, 206 Process *p, ThreadContext *tc); 207 208/// Target lseek() handler. 209SyscallReturn lseekFunc(SyscallDesc *desc, int num, 210 Process *p, ThreadContext *tc); 211 212/// Target munmap() handler. 213SyscallReturn munmapFunc(SyscallDesc *desc, int num, 214 Process *p, ThreadContext *tc); 215 216/// Target gethostname() handler. 217SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 218 Process *p, ThreadContext *tc); 219 220/// Target unlink() handler. 221SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 222 Process *p, ThreadContext *tc); 223 224/// Target rename() handler. 225SyscallReturn renameFunc(SyscallDesc *desc, int num, 226 Process *p, ThreadContext *tc); 227 228 229/// Target truncate() handler. 230SyscallReturn truncateFunc(SyscallDesc *desc, int num, 231 Process *p, ThreadContext *tc); 232 233 234/// Target ftruncate() handler. 235SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 236 Process *p, ThreadContext *tc); 237 238 239/// Target chown() handler. 240SyscallReturn chownFunc(SyscallDesc *desc, int num, 241 Process *p, ThreadContext *tc); 242 243 244/// Target fchown() handler. 245SyscallReturn fchownFunc(SyscallDesc *desc, int num, 246 Process *p, ThreadContext *tc); 247 248/// Target fnctl() handler. 249SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 250 Process *process, ThreadContext *tc); 251 252/// Target fcntl64() handler. 253SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 254 Process *process, ThreadContext *tc); 255 256/// Target setuid() handler. 257SyscallReturn setuidFunc(SyscallDesc *desc, int num, 258 Process *p, ThreadContext *tc); 259 260/// Target getpid() handler. 261SyscallReturn getpidFunc(SyscallDesc *desc, int num, 262 Process *p, ThreadContext *tc); 263 264/// Target getuid() handler. 265SyscallReturn getuidFunc(SyscallDesc *desc, int num, 266 Process *p, ThreadContext *tc); 267 268/// Target getgid() handler. 269SyscallReturn getgidFunc(SyscallDesc *desc, int num, 270 Process *p, ThreadContext *tc); 271 272/// Target getppid() handler. 273SyscallReturn getppidFunc(SyscallDesc *desc, int num, 274 Process *p, ThreadContext *tc); 275 276/// Target geteuid() handler. 277SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 278 Process *p, ThreadContext *tc); 279 280/// Target getegid() handler. 281SyscallReturn getegidFunc(SyscallDesc *desc, int num, 282 Process *p, ThreadContext *tc); 283 284 285 286/// Pseudo Funcs - These functions use a different return convension, 287/// returning a second value in a register other than the normal return register 288SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 289 Process *process, ThreadContext *tc); 290 291/// Target getpidPseudo() handler. 292SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 293 Process *p, ThreadContext *tc); 294 295/// Target getuidPseudo() handler. 296SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 297 Process *p, ThreadContext *tc); 298 299/// Target getgidPseudo() handler. 300SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 301 Process *p, ThreadContext *tc); 302 303 304/// This struct is used to build an target-OS-dependent table that 305/// maps the target's open() flags to the host open() flags. 306struct OpenFlagTransTable { 307 int tgtFlag; //!< Target system flag value. 308 int hostFlag; //!< Corresponding host system flag value. 309}; 310 311 312 313/// A readable name for 1,000,000, for converting microseconds to seconds. 314const int one_million = 1000000; 315 316/// Approximate seconds since the epoch (1/1/1970). About a billion, 317/// by my reckoning. We want to keep this a constant (not use the 318/// real-world time) to keep simulations repeatable. 319const unsigned seconds_since_epoch = 1000000000; 320 321/// Helper function to convert current elapsed time to seconds and 322/// microseconds. 323template <class T1, class T2> 324void 325getElapsedTime(T1 &sec, T2 &usec) 326{ 327 int elapsed_usecs = curTick / Clock::Int::us; 328 sec = elapsed_usecs / one_million; 329 usec = elapsed_usecs % one_million; 330} 331 332////////////////////////////////////////////////////////////////////// 333// 334// The following emulation functions are generic, but need to be 335// templated to account for differences in types, constants, etc. 336// 337////////////////////////////////////////////////////////////////////// 338 339/// Target ioctl() handler. For the most part, programs call ioctl() 340/// only to find out if their stdout is a tty, to determine whether to 341/// do line or block buffering. 342template <class OS> 343SyscallReturn 344ioctlFunc(SyscallDesc *desc, int callnum, Process *process, 345 ThreadContext *tc) 346{ 347 int fd = tc->getSyscallArg(0); 348 unsigned req = tc->getSyscallArg(1); 349 350 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 351 352 if (fd < 0 || process->sim_fd(fd) < 0) { 353 // doesn't map to any simulator fd: not a valid target fd 354 return -EBADF; 355 } 356 357 switch (req) { 358 case OS::TIOCISATTY: 359 case OS::TIOCGETP: 360 case OS::TIOCSETP: 361 case OS::TIOCSETN: 362 case OS::TIOCSETC: 363 case OS::TIOCGETC: 364 case OS::TIOCGETS: 365 case OS::TIOCGETA: 366 return -ENOTTY; 367 368 default: 369 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 370 fd, req, tc->readPC()); 371 } 372} 373 374/// Target open() handler. 375template <class OS> 376SyscallReturn 377openFunc(SyscallDesc *desc, int callnum, Process *process, 378 ThreadContext *tc) 379{ 380 std::string path; 381 382 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 383 return -EFAULT; 384 385 if (path == "/dev/sysdev0") { 386 // This is a memory-mapped high-resolution timer device on Alpha. 387 // We don't support it, so just punt. 388 warn("Ignoring open(%s, ...)\n", path); 389 return -ENOENT; 390 } 391 392 int tgtFlags = tc->getSyscallArg(1); 393 int mode = tc->getSyscallArg(2); 394 int hostFlags = 0; 395 396 // translate open flags 397 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 398 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 399 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 400 hostFlags |= OS::openFlagTable[i].hostFlag; 401 } 402 } 403 404 // any target flags left? 405 if (tgtFlags != 0) 406 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 407 408#ifdef __CYGWIN32__ 409 hostFlags |= O_BINARY; 410#endif 411 412 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 413 414 // open the file 415 int fd = open(path.c_str(), hostFlags, mode); 416 417 return (fd == -1) ? -errno : process->alloc_fd(fd); 418} 419 420 421/// Target chmod() handler. 422template <class OS> 423SyscallReturn 424chmodFunc(SyscallDesc *desc, int callnum, Process *process, 425 ThreadContext *tc) 426{ 427 std::string path; 428 429 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 430 return -EFAULT; 431 432 uint32_t mode = tc->getSyscallArg(1); 433 mode_t hostMode = 0; 434 435 // XXX translate mode flags via OS::something??? 436 hostMode = mode; 437 438 // do the chmod 439 int result = chmod(path.c_str(), hostMode); 440 if (result < 0) 441 return -errno; 442 443 return 0; 444} 445 446 447/// Target fchmod() handler. 448template <class OS> 449SyscallReturn 450fchmodFunc(SyscallDesc *desc, int callnum, Process *process, 451 ThreadContext *tc) 452{ 453 int fd = tc->getSyscallArg(0); 454 if (fd < 0 || process->sim_fd(fd) < 0) { 455 // doesn't map to any simulator fd: not a valid target fd 456 return -EBADF; 457 } 458 459 uint32_t mode = tc->getSyscallArg(1); 460 mode_t hostMode = 0; 461 462 // XXX translate mode flags via OS::someting??? 463 hostMode = mode; 464 465 // do the fchmod 466 int result = fchmod(process->sim_fd(fd), hostMode); 467 if (result < 0) 468 return -errno; 469 470 return 0; 471} 472 473 474/// Target stat() handler. 475template <class OS> 476SyscallReturn 477statFunc(SyscallDesc *desc, int callnum, Process *process, 478 ThreadContext *tc) 479{ 480 std::string path; 481 482 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 483 return -EFAULT; 484 485 struct stat hostBuf; 486 int result = stat(path.c_str(), &hostBuf); 487 488 if (result < 0) 489 return -errno; 490 491 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 492 493 return 0; 494} 495 496 497/// Target fstat64() handler. 498template <class OS> 499SyscallReturn 500fstat64Func(SyscallDesc *desc, int callnum, Process *process, 501 ThreadContext *tc) 502{ 503 int fd = tc->getSyscallArg(0); 504 if (fd < 0 || process->sim_fd(fd) < 0) { 505 // doesn't map to any simulator fd: not a valid target fd 506 return -EBADF; 507 } 508 509#if BSD_HOST 510 struct stat hostBuf; 511 int result = fstat(process->sim_fd(fd), &hostBuf); 512#else 513 struct stat64 hostBuf; 514 int result = fstat64(process->sim_fd(fd), &hostBuf); 515#endif 516 517 if (result < 0) 518 return -errno; 519 520 OS::copyOutStat64Buf(tc->getMemPort(), fd, tc->getSyscallArg(1), &hostBuf); 521 522 return 0; 523} 524 525 526/// Target lstat() handler. 527template <class OS> 528SyscallReturn 529lstatFunc(SyscallDesc *desc, int callnum, Process *process, 530 ThreadContext *tc) 531{ 532 std::string path; 533 534 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 535 return -EFAULT; 536 537 struct stat hostBuf; 538 int result = lstat(path.c_str(), &hostBuf); 539 540 if (result < 0) 541 return -errno; 542 543 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 544 545 return 0; 546} 547 548/// Target lstat64() handler. 549template <class OS> 550SyscallReturn 551lstat64Func(SyscallDesc *desc, int callnum, Process *process, 552 ThreadContext *tc) 553{ 554 std::string path; 555 556 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 557 return -EFAULT; 558 559#if BSD_HOST 560 struct stat hostBuf; 561 int result = lstat(path.c_str(), &hostBuf); 562#else 563 struct stat64 hostBuf; 564 int result = lstat64(path.c_str(), &hostBuf); 565#endif 566 567 if (result < 0) 568 return -errno; 569 570 OS::copyOutStat64Buf(tc->getMemPort(), -1, tc->getSyscallArg(1), &hostBuf); 571 572 return 0; 573} 574 575/// Target fstat() handler. 576template <class OS> 577SyscallReturn 578fstatFunc(SyscallDesc *desc, int callnum, Process *process, 579 ThreadContext *tc) 580{ 581 int fd = process->sim_fd(tc->getSyscallArg(0)); 582 583 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 584 585 if (fd < 0) 586 return -EBADF; 587 588 struct stat hostBuf; 589 int result = fstat(fd, &hostBuf); 590 591 if (result < 0) 592 return -errno; 593 594 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 595 596 return 0; 597} 598 599 600/// Target statfs() handler. 601template <class OS> 602SyscallReturn 603statfsFunc(SyscallDesc *desc, int callnum, Process *process, 604 ThreadContext *tc) 605{ 606 std::string path; 607 608 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 609 return -EFAULT; 610 611 struct statfs hostBuf; 612 int result = statfs(path.c_str(), &hostBuf); 613 614 if (result < 0) 615 return -errno; 616 617 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 618 619 return 0; 620} 621 622 623/// Target fstatfs() handler. 624template <class OS> 625SyscallReturn 626fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, 627 ThreadContext *tc) 628{ 629 int fd = process->sim_fd(tc->getSyscallArg(0)); 630 631 if (fd < 0) 632 return -EBADF; 633 634 struct statfs hostBuf; 635 int result = fstatfs(fd, &hostBuf); 636 637 if (result < 0) 638 return -errno; 639 640 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 641 642 return 0; 643} 644 645 646/// Target writev() handler. 647template <class OS> 648SyscallReturn 649writevFunc(SyscallDesc *desc, int callnum, Process *process, 650 ThreadContext *tc) 651{ 652 int fd = tc->getSyscallArg(0); 653 if (fd < 0 || process->sim_fd(fd) < 0) { 654 // doesn't map to any simulator fd: not a valid target fd 655 return -EBADF; 656 } 657 658 TranslatingPort *p = tc->getMemPort(); 659 uint64_t tiov_base = tc->getSyscallArg(1); 660 size_t count = tc->getSyscallArg(2); 661 struct iovec hiov[count]; 662 for (int i = 0; i < count; ++i) 663 { 664 typename OS::tgt_iovec tiov; 665 666 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 667 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 668 hiov[i].iov_len = gtoh(tiov.iov_len); 669 hiov[i].iov_base = new char [hiov[i].iov_len]; 670 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 671 hiov[i].iov_len); 672 } 673 674 int result = writev(process->sim_fd(fd), hiov, count); 675 676 for (int i = 0; i < count; ++i) 677 { 678 delete [] (char *)hiov[i].iov_base; 679 } 680 681 if (result < 0) 682 return -errno; 683 684 return 0; 685} 686 687 688/// Target mmap() handler. 689/// 690/// We don't really handle mmap(). If the target is mmaping an 691/// anonymous region or /dev/zero, we can get away with doing basically 692/// nothing (since memory is initialized to zero and the simulator 693/// doesn't really check addresses anyway). Always print a warning, 694/// since this could be seriously broken if we're not mapping 695/// /dev/zero. 696// 697/// Someday we should explicitly check for /dev/zero in open, flag the 698/// file descriptor, and fail (or implement!) a non-anonymous mmap to 699/// anything else. 700template <class OS> 701SyscallReturn 702mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 703{ 704 Addr start = tc->getSyscallArg(0); 705 uint64_t length = tc->getSyscallArg(1); 706 // int prot = tc->getSyscallArg(2); 707 int flags = tc->getSyscallArg(3); 708 // int fd = p->sim_fd(tc->getSyscallArg(4)); 709 // int offset = tc->getSyscallArg(5); 710 711 if ((start % TheISA::VMPageSize) != 0 || 712 (length % TheISA::VMPageSize) != 0) { 713 warn("mmap failing: arguments not page-aligned: " 714 "start 0x%x length 0x%x", 715 start, length); 716 return -EINVAL; 717 } 718 719 if (start != 0) { 720 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 721 start, p->mmap_end); 722 } 723 724 // pick next address from our "mmap region" 725 start = p->mmap_end; 726 p->pTable->allocate(start, length); 727 p->mmap_end += length; 728 729 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 730 warn("allowing mmap of file @ fd %d. " 731 "This will break if not /dev/zero.", tc->getSyscallArg(4)); 732 } 733 734 return start; 735} 736 737/// Target getrlimit() handler. 738template <class OS> 739SyscallReturn 740getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 741 ThreadContext *tc) 742{ 743 unsigned resource = tc->getSyscallArg(0); 744 TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); 745 746 switch (resource) { 747 case OS::TGT_RLIMIT_STACK: 748 // max stack size in bytes: make up a number (2MB for now) 749 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 750 rlp->rlim_cur = htog(rlp->rlim_cur); 751 rlp->rlim_max = htog(rlp->rlim_max); 752 break; 753 754 default: 755 std::cerr << "getrlimitFunc: unimplemented resource " << resource 756 << std::endl; 757 abort(); 758 break; 759 } 760 761 rlp.copyOut(tc->getMemPort()); 762 return 0; 763} 764 765/// Target gettimeofday() handler. 766template <class OS> 767SyscallReturn 768gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 769 ThreadContext *tc) 770{ 771 TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); 772 773 getElapsedTime(tp->tv_sec, tp->tv_usec); 774 tp->tv_sec += seconds_since_epoch; 775 tp->tv_sec = htog(tp->tv_sec); 776 tp->tv_usec = htog(tp->tv_usec); 777 778 tp.copyOut(tc->getMemPort()); 779 780 return 0; 781} 782 783 784/// Target utimes() handler. 785template <class OS> 786SyscallReturn 787utimesFunc(SyscallDesc *desc, int callnum, Process *process, 788 ThreadContext *tc) 789{ 790 std::string path; 791 792 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 793 return -EFAULT; 794 795 TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); 796 tp.copyIn(tc->getMemPort()); 797 798 struct timeval hostTimeval[2]; 799 for (int i = 0; i < 2; ++i) 800 { 801 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 802 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 803 } 804 int result = utimes(path.c_str(), hostTimeval); 805 806 if (result < 0) 807 return -errno; 808 809 return 0; 810} 811/// Target getrusage() function. 812template <class OS> 813SyscallReturn 814getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 815 ThreadContext *tc) 816{ 817 int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 818 TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); 819 820 if (who != OS::TGT_RUSAGE_SELF) { 821 // don't really handle THREAD or CHILDREN, but just warn and 822 // plow ahead 823 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 824 who); 825 } 826 827 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 828 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 829 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 830 831 rup->ru_stime.tv_sec = 0; 832 rup->ru_stime.tv_usec = 0; 833 rup->ru_maxrss = 0; 834 rup->ru_ixrss = 0; 835 rup->ru_idrss = 0; 836 rup->ru_isrss = 0; 837 rup->ru_minflt = 0; 838 rup->ru_majflt = 0; 839 rup->ru_nswap = 0; 840 rup->ru_inblock = 0; 841 rup->ru_oublock = 0; 842 rup->ru_msgsnd = 0; 843 rup->ru_msgrcv = 0; 844 rup->ru_nsignals = 0; 845 rup->ru_nvcsw = 0; 846 rup->ru_nivcsw = 0; 847 848 rup.copyOut(tc->getMemPort()); 849 850 return 0; 851} 852 853 854 855 856#endif // __SIM_SYSCALL_EMUL_HH__ 857