syscall_emul.hh revision 3277
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 NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 36 defined(__FreeBSD__) || defined(__CYGWIN__)) 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/stat.h> 50#include <fcntl.h> 51#include <sys/uio.h> 52 53#include "sim/host.hh" // for Addr 54#include "base/chunk_generator.hh" 55#include "base/intmath.hh" // for RoundUp 56#include "base/misc.hh" 57#include "base/trace.hh" 58#include "cpu/base.hh" 59#include "cpu/thread_context.hh" 60#include "mem/translating_port.hh" 61#include "mem/page_table.hh" 62#include "sim/process.hh" 63 64/// 65/// System call descriptor. 66/// 67class SyscallDesc { 68 69 public: 70 71 /// Typedef for target syscall handler functions. 72 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 73 LiveProcess *, ThreadContext *); 74 75 const char *name; //!< Syscall name (e.g., "open"). 76 FuncPtr funcPtr; //!< Pointer to emulation function. 77 int flags; //!< Flags (see Flags enum). 78 79 /// Flag values for controlling syscall behavior. 80 enum Flags { 81 /// Don't set return regs according to funcPtr return value. 82 /// Used for syscalls with non-standard return conventions 83 /// that explicitly set the ThreadContext regs (e.g., 84 /// sigreturn). 85 SuppressReturnValue = 1 86 }; 87 88 /// Constructor. 89 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 90 : name(_name), funcPtr(_funcPtr), flags(_flags) 91 { 92 } 93 94 /// Emulate the syscall. Public interface for calling through funcPtr. 95 void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 96}; 97 98 99class BaseBufferArg { 100 101 public: 102 103 BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 104 { 105 bufPtr = new uint8_t[size]; 106 // clear out buffer: in case we only partially populate this, 107 // and then do a copyOut(), we want to make sure we don't 108 // introduce any random junk into the simulated address space 109 memset(bufPtr, 0, size); 110 } 111 112 virtual ~BaseBufferArg() { delete [] bufPtr; } 113 114 // 115 // copy data into simulator space (read from target memory) 116 // 117 virtual bool copyIn(TranslatingPort *memport) 118 { 119 memport->readBlob(addr, bufPtr, size); 120 return true; // no EFAULT detection for now 121 } 122 123 // 124 // copy data out of simulator space (write to target memory) 125 // 126 virtual bool copyOut(TranslatingPort *memport) 127 { 128 memport->writeBlob(addr, bufPtr, size); 129 return true; // no EFAULT detection for now 130 } 131 132 protected: 133 Addr addr; 134 int size; 135 uint8_t *bufPtr; 136}; 137 138 139class BufferArg : public BaseBufferArg 140{ 141 public: 142 BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 143 void *bufferPtr() { return bufPtr; } 144}; 145 146template <class T> 147class TypedBufferArg : public BaseBufferArg 148{ 149 public: 150 // user can optionally specify a specific number of bytes to 151 // allocate to deal with those structs that have variable-size 152 // arrays at the end 153 TypedBufferArg(Addr _addr, int _size = sizeof(T)) 154 : BaseBufferArg(_addr, _size) 155 { } 156 157 // type case 158 operator T*() { return (T *)bufPtr; } 159 160 // dereference operators 161 T &operator*() { return *((T *)bufPtr); } 162 T* operator->() { return (T *)bufPtr; } 163 T &operator[](int i) { return ((T *)bufPtr)[i]; } 164}; 165 166////////////////////////////////////////////////////////////////////// 167// 168// The following emulation functions are generic enough that they 169// don't need to be recompiled for different emulated OS's. They are 170// defined in sim/syscall_emul.cc. 171// 172////////////////////////////////////////////////////////////////////// 173 174 175/// Handler for unimplemented syscalls that we haven't thought about. 176SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 177 LiveProcess *p, ThreadContext *tc); 178 179/// Handler for unimplemented syscalls that we never intend to 180/// implement (signal handling, etc.) and should not affect the correct 181/// behavior of the program. Print a warning only if the appropriate 182/// trace flag is enabled. Return success to the target program. 183SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 184 LiveProcess *p, ThreadContext *tc); 185 186/// Target exit() handler: terminate simulation. 187SyscallReturn exitFunc(SyscallDesc *desc, int num, 188 LiveProcess *p, ThreadContext *tc); 189 190/// Target getpagesize() handler. 191SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 192 LiveProcess *p, ThreadContext *tc); 193 194/// Target obreak() handler: set brk address. 195SyscallReturn obreakFunc(SyscallDesc *desc, int num, 196 LiveProcess *p, ThreadContext *tc); 197 198/// Target close() handler. 199SyscallReturn closeFunc(SyscallDesc *desc, int num, 200 LiveProcess *p, ThreadContext *tc); 201 202/// Target read() handler. 203SyscallReturn readFunc(SyscallDesc *desc, int num, 204 LiveProcess *p, ThreadContext *tc); 205 206/// Target write() handler. 207SyscallReturn writeFunc(SyscallDesc *desc, int num, 208 LiveProcess *p, ThreadContext *tc); 209 210/// Target lseek() handler. 211SyscallReturn lseekFunc(SyscallDesc *desc, int num, 212 LiveProcess *p, ThreadContext *tc); 213 214/// Target munmap() handler. 215SyscallReturn munmapFunc(SyscallDesc *desc, int num, 216 LiveProcess *p, ThreadContext *tc); 217 218/// Target gethostname() handler. 219SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 220 LiveProcess *p, ThreadContext *tc); 221 222/// Target unlink() handler. 223SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 224 LiveProcess *p, ThreadContext *tc); 225 226/// Target rename() handler. 227SyscallReturn renameFunc(SyscallDesc *desc, int num, 228 LiveProcess *p, ThreadContext *tc); 229 230 231/// Target truncate() handler. 232SyscallReturn truncateFunc(SyscallDesc *desc, int num, 233 LiveProcess *p, ThreadContext *tc); 234 235 236/// Target ftruncate() handler. 237SyscallReturn ftruncateFunc(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 291 292/// Pseudo Funcs - These functions use a different return convension, 293/// returning a second value in a register other than the normal return register 294SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 295 LiveProcess *process, ThreadContext *tc); 296 297/// Target getpidPseudo() handler. 298SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 299 LiveProcess *p, ThreadContext *tc); 300 301/// Target getuidPseudo() handler. 302SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 303 LiveProcess *p, ThreadContext *tc); 304 305/// Target getgidPseudo() handler. 306SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 307 LiveProcess *p, ThreadContext *tc); 308 309 310/// A readable name for 1,000,000, for converting microseconds to seconds. 311const int one_million = 1000000; 312 313/// Approximate seconds since the epoch (1/1/1970). About a billion, 314/// by my reckoning. We want to keep this a constant (not use the 315/// real-world time) to keep simulations repeatable. 316const unsigned seconds_since_epoch = 1000000000; 317 318/// Helper function to convert current elapsed time to seconds and 319/// microseconds. 320template <class T1, class T2> 321void 322getElapsedTime(T1 &sec, T2 &usec) 323{ 324 int elapsed_usecs = curTick / Clock::Int::us; 325 sec = elapsed_usecs / one_million; 326 usec = elapsed_usecs % one_million; 327} 328 329////////////////////////////////////////////////////////////////////// 330// 331// The following emulation functions are generic, but need to be 332// templated to account for differences in types, constants, etc. 333// 334////////////////////////////////////////////////////////////////////// 335 336#if NO_STAT64 337 typedef struct stat hst_stat; 338 typedef struct stat hst_stat64; 339#else 340 typedef struct stat hst_stat; 341 typedef struct stat64 hst_stat64; 342#endif 343 344//// Helper function to convert a host stat buffer to a target stat 345//// buffer. Also copies the target buffer out to the simulated 346//// memory space. Used by stat(), fstat(), and lstat(). 347 348template <typename target_stat, typename host_stat> 349static void 350convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 351{ 352 if (fakeTTY) 353 tgt->st_dev = 0xA; 354 else 355 tgt->st_dev = host->st_dev; 356 tgt->st_dev = htog(tgt->st_dev); 357 tgt->st_ino = host->st_ino; 358 tgt->st_ino = htog(tgt->st_ino); 359 tgt->st_mode = host->st_mode; 360 tgt->st_mode = htog(tgt->st_mode); 361 tgt->st_nlink = host->st_nlink; 362 tgt->st_nlink = htog(tgt->st_nlink); 363 tgt->st_uid = host->st_uid; 364 tgt->st_uid = htog(tgt->st_uid); 365 tgt->st_gid = host->st_gid; 366 tgt->st_gid = htog(tgt->st_gid); 367 if (fakeTTY) 368 tgt->st_rdev = 0x880d; 369 else 370 tgt->st_rdev = host->st_rdev; 371 tgt->st_rdev = htog(tgt->st_rdev); 372 tgt->st_size = host->st_size; 373 tgt->st_size = htog(tgt->st_size); 374 tgt->st_atimeX = host->st_atime; 375 tgt->st_atimeX = htog(tgt->st_atimeX); 376 tgt->st_mtimeX = host->st_mtime; 377 tgt->st_mtimeX = htog(tgt->st_mtimeX); 378 tgt->st_ctimeX = host->st_ctime; 379 tgt->st_ctimeX = htog(tgt->st_ctimeX); 380 tgt->st_blksize = host->st_blksize; 381 tgt->st_blksize = htog(tgt->st_blksize); 382 tgt->st_blocks = host->st_blocks; 383 tgt->st_blocks = htog(tgt->st_blocks); 384} 385 386// Same for stat64 387 388template <typename target_stat, typename host_stat64> 389static void 390convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 391{ 392 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 393#if defined(STAT_HAVE_NSEC) 394 tgt->st_atime_nsec = host->st_atime_nsec; 395 tgt->st_atime_nsec = htog(tgt->st_atime_nsec); 396 tgt->st_mtime_nsec = host->st_mtime_nsec; 397 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec); 398 tgt->st_ctime_nsec = host->st_ctime_nsec; 399 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec); 400#else 401 tgt->st_atime_nsec = 0; 402 tgt->st_mtime_nsec = 0; 403 tgt->st_ctime_nsec = 0; 404#endif 405} 406 407//Here are a couple convenience functions 408template<class OS> 409static void 410copyOutStatBuf(TranslatingPort * mem, Addr addr, 411 hst_stat *host, bool fakeTTY = false) 412{ 413 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 414 tgt_stat_buf tgt(addr); 415 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 416 tgt.copyOut(mem); 417} 418 419template<class OS> 420static void 421copyOutStat64Buf(TranslatingPort * mem, Addr addr, 422 hst_stat64 *host, bool fakeTTY = false) 423{ 424 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 425 tgt_stat_buf tgt(addr); 426 convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 427 tgt.copyOut(mem); 428} 429 430/// Target ioctl() handler. For the most part, programs call ioctl() 431/// only to find out if their stdout is a tty, to determine whether to 432/// do line or block buffering. 433template <class OS> 434SyscallReturn 435ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 436 ThreadContext *tc) 437{ 438 int fd = tc->getSyscallArg(0); 439 unsigned req = tc->getSyscallArg(1); 440 441 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 442 443 if (fd < 0 || process->sim_fd(fd) < 0) { 444 // doesn't map to any simulator fd: not a valid target fd 445 return -EBADF; 446 } 447 448 switch (req) { 449 case OS::TIOCISATTY: 450 case OS::TIOCGETP: 451 case OS::TIOCSETP: 452 case OS::TIOCSETN: 453 case OS::TIOCSETC: 454 case OS::TIOCGETC: 455 case OS::TIOCGETS: 456 case OS::TIOCGETA: 457 return -ENOTTY; 458 459 default: 460 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 461 fd, req, tc->readPC()); 462 } 463} 464 465/// Target open() handler. 466template <class OS> 467SyscallReturn 468openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 469 ThreadContext *tc) 470{ 471 std::string path; 472 473 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 474 return -EFAULT; 475 476 if (path == "/dev/sysdev0") { 477 // This is a memory-mapped high-resolution timer device on Alpha. 478 // We don't support it, so just punt. 479 warn("Ignoring open(%s, ...)\n", path); 480 return -ENOENT; 481 } 482 483 int tgtFlags = tc->getSyscallArg(1); 484 int mode = tc->getSyscallArg(2); 485 int hostFlags = 0; 486 487 // translate open flags 488 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 489 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 490 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 491 hostFlags |= OS::openFlagTable[i].hostFlag; 492 } 493 } 494 495 // any target flags left? 496 if (tgtFlags != 0) 497 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 498 499#ifdef __CYGWIN32__ 500 hostFlags |= O_BINARY; 501#endif 502 503 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 504 505 // open the file 506 int fd = open(path.c_str(), hostFlags, mode); 507 508 return (fd == -1) ? -errno : process->alloc_fd(fd); 509} 510 511 512/// Target chmod() handler. 513template <class OS> 514SyscallReturn 515chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 516 ThreadContext *tc) 517{ 518 std::string path; 519 520 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 521 return -EFAULT; 522 523 uint32_t mode = tc->getSyscallArg(1); 524 mode_t hostMode = 0; 525 526 // XXX translate mode flags via OS::something??? 527 hostMode = mode; 528 529 // do the chmod 530 int result = chmod(path.c_str(), hostMode); 531 if (result < 0) 532 return -errno; 533 534 return 0; 535} 536 537 538/// Target fchmod() handler. 539template <class OS> 540SyscallReturn 541fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 542 ThreadContext *tc) 543{ 544 int fd = tc->getSyscallArg(0); 545 if (fd < 0 || process->sim_fd(fd) < 0) { 546 // doesn't map to any simulator fd: not a valid target fd 547 return -EBADF; 548 } 549 550 uint32_t mode = tc->getSyscallArg(1); 551 mode_t hostMode = 0; 552 553 // XXX translate mode flags via OS::someting??? 554 hostMode = mode; 555 556 // do the fchmod 557 int result = fchmod(process->sim_fd(fd), hostMode); 558 if (result < 0) 559 return -errno; 560 561 return 0; 562} 563 564 565/// Target stat() handler. 566template <class OS> 567SyscallReturn 568statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 569 ThreadContext *tc) 570{ 571 std::string path; 572 573 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 574 return -EFAULT; 575 576 struct stat hostBuf; 577 int result = stat(path.c_str(), &hostBuf); 578 579 if (result < 0) 580 return -errno; 581 582 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 583 584 return 0; 585} 586 587 588/// Target fstat64() handler. 589template <class OS> 590SyscallReturn 591fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 592 ThreadContext *tc) 593{ 594 int fd = tc->getSyscallArg(0); 595 if (fd < 0 || process->sim_fd(fd) < 0) { 596 // doesn't map to any simulator fd: not a valid target fd 597 return -EBADF; 598 } 599 600#if NO_STAT64 601 struct stat hostBuf; 602 int result = fstat(process->sim_fd(fd), &hostBuf); 603#else 604 struct stat64 hostBuf; 605 int result = fstat64(process->sim_fd(fd), &hostBuf); 606#endif 607 608 if (result < 0) 609 return -errno; 610 611 copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), 612 &hostBuf, (fd == 1)); 613 614 return 0; 615} 616 617 618/// Target lstat() handler. 619template <class OS> 620SyscallReturn 621lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 622 ThreadContext *tc) 623{ 624 std::string path; 625 626 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 627 return -EFAULT; 628 629 struct stat hostBuf; 630 int result = lstat(path.c_str(), &hostBuf); 631 632 if (result < 0) 633 return -errno; 634 635 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 636 637 return 0; 638} 639 640/// Target lstat64() handler. 641template <class OS> 642SyscallReturn 643lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 644 ThreadContext *tc) 645{ 646 std::string path; 647 648 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 649 return -EFAULT; 650 651#if NO_STAT64 652 struct stat hostBuf; 653 int result = lstat(path.c_str(), &hostBuf); 654#else 655 struct stat64 hostBuf; 656 int result = lstat64(path.c_str(), &hostBuf); 657#endif 658 659 if (result < 0) 660 return -errno; 661 662 copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 663 664 return 0; 665} 666 667/// Target fstat() handler. 668template <class OS> 669SyscallReturn 670fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 671 ThreadContext *tc) 672{ 673 int fd = process->sim_fd(tc->getSyscallArg(0)); 674 675 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 676 677 if (fd < 0) 678 return -EBADF; 679 680 struct stat hostBuf; 681 int result = fstat(fd, &hostBuf); 682 683 if (result < 0) 684 return -errno; 685 686 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), 687 &hostBuf, (fd == 1)); 688 689 return 0; 690} 691 692 693/// Target statfs() handler. 694template <class OS> 695SyscallReturn 696statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 697 ThreadContext *tc) 698{ 699 std::string path; 700 701 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 702 return -EFAULT; 703 704 struct statfs hostBuf; 705 int result = statfs(path.c_str(), &hostBuf); 706 707 if (result < 0) 708 return -errno; 709 710 OS::copyOutStatfsBuf(tc->getMemPort(), 711 (Addr)(tc->getSyscallArg(1)), &hostBuf); 712 713 return 0; 714} 715 716 717/// Target fstatfs() handler. 718template <class OS> 719SyscallReturn 720fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 721 ThreadContext *tc) 722{ 723 int fd = process->sim_fd(tc->getSyscallArg(0)); 724 725 if (fd < 0) 726 return -EBADF; 727 728 struct statfs hostBuf; 729 int result = fstatfs(fd, &hostBuf); 730 731 if (result < 0) 732 return -errno; 733 734 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), 735 &hostBuf); 736 737 return 0; 738} 739 740 741/// Target writev() handler. 742template <class OS> 743SyscallReturn 744writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 745 ThreadContext *tc) 746{ 747 int fd = tc->getSyscallArg(0); 748 if (fd < 0 || process->sim_fd(fd) < 0) { 749 // doesn't map to any simulator fd: not a valid target fd 750 return -EBADF; 751 } 752 753 TranslatingPort *p = tc->getMemPort(); 754 uint64_t tiov_base = tc->getSyscallArg(1); 755 size_t count = tc->getSyscallArg(2); 756 struct iovec hiov[count]; 757 for (int i = 0; i < count; ++i) 758 { 759 typename OS::tgt_iovec tiov; 760 761 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 762 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 763 hiov[i].iov_len = gtoh(tiov.iov_len); 764 hiov[i].iov_base = new char [hiov[i].iov_len]; 765 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 766 hiov[i].iov_len); 767 } 768 769 int result = writev(process->sim_fd(fd), hiov, count); 770 771 for (int i = 0; i < count; ++i) 772 { 773 delete [] (char *)hiov[i].iov_base; 774 } 775 776 if (result < 0) 777 return -errno; 778 779 return 0; 780} 781 782 783/// Target mmap() handler. 784/// 785/// We don't really handle mmap(). If the target is mmaping an 786/// anonymous region or /dev/zero, we can get away with doing basically 787/// nothing (since memory is initialized to zero and the simulator 788/// doesn't really check addresses anyway). Always print a warning, 789/// since this could be seriously broken if we're not mapping 790/// /dev/zero. 791// 792/// Someday we should explicitly check for /dev/zero in open, flag the 793/// file descriptor, and fail (or implement!) a non-anonymous mmap to 794/// anything else. 795template <class OS> 796SyscallReturn 797mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 798{ 799 Addr start = tc->getSyscallArg(0); 800 uint64_t length = tc->getSyscallArg(1); 801 // int prot = tc->getSyscallArg(2); 802 int flags = tc->getSyscallArg(3); 803 // int fd = p->sim_fd(tc->getSyscallArg(4)); 804 // int offset = tc->getSyscallArg(5); 805 806 if ((start % TheISA::VMPageSize) != 0 || 807 (length % TheISA::VMPageSize) != 0) { 808 warn("mmap failing: arguments not page-aligned: " 809 "start 0x%x length 0x%x", 810 start, length); 811 return -EINVAL; 812 } 813 814 if (start != 0) { 815 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 816 start, p->mmap_end); 817 } 818 819 // pick next address from our "mmap region" 820 start = p->mmap_end; 821 p->pTable->allocate(start, length); 822 p->mmap_end += length; 823 824 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 825 warn("allowing mmap of file @ fd %d. " 826 "This will break if not /dev/zero.", tc->getSyscallArg(4)); 827 } 828 829 return start; 830} 831 832/// Target getrlimit() handler. 833template <class OS> 834SyscallReturn 835getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 836 ThreadContext *tc) 837{ 838 unsigned resource = tc->getSyscallArg(0); 839 TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); 840 841 switch (resource) { 842 case OS::TGT_RLIMIT_STACK: 843 // max stack size in bytes: make up a number (2MB for now) 844 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 845 rlp->rlim_cur = htog(rlp->rlim_cur); 846 rlp->rlim_max = htog(rlp->rlim_max); 847 break; 848 849 default: 850 std::cerr << "getrlimitFunc: unimplemented resource " << resource 851 << std::endl; 852 abort(); 853 break; 854 } 855 856 rlp.copyOut(tc->getMemPort()); 857 return 0; 858} 859 860/// Target gettimeofday() handler. 861template <class OS> 862SyscallReturn 863gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 864 ThreadContext *tc) 865{ 866 TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); 867 868 getElapsedTime(tp->tv_sec, tp->tv_usec); 869 tp->tv_sec += seconds_since_epoch; 870 tp->tv_sec = htog(tp->tv_sec); 871 tp->tv_usec = htog(tp->tv_usec); 872 873 tp.copyOut(tc->getMemPort()); 874 875 return 0; 876} 877 878 879/// Target utimes() handler. 880template <class OS> 881SyscallReturn 882utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 883 ThreadContext *tc) 884{ 885 std::string path; 886 887 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 888 return -EFAULT; 889 890 TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); 891 tp.copyIn(tc->getMemPort()); 892 893 struct timeval hostTimeval[2]; 894 for (int i = 0; i < 2; ++i) 895 { 896 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 897 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 898 } 899 int result = utimes(path.c_str(), hostTimeval); 900 901 if (result < 0) 902 return -errno; 903 904 return 0; 905} 906/// Target getrusage() function. 907template <class OS> 908SyscallReturn 909getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 910 ThreadContext *tc) 911{ 912 int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 913 TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); 914 915 if (who != OS::TGT_RUSAGE_SELF) { 916 // don't really handle THREAD or CHILDREN, but just warn and 917 // plow ahead 918 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 919 who); 920 } 921 922 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 923 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 924 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 925 926 rup->ru_stime.tv_sec = 0; 927 rup->ru_stime.tv_usec = 0; 928 rup->ru_maxrss = 0; 929 rup->ru_ixrss = 0; 930 rup->ru_idrss = 0; 931 rup->ru_isrss = 0; 932 rup->ru_minflt = 0; 933 rup->ru_majflt = 0; 934 rup->ru_nswap = 0; 935 rup->ru_inblock = 0; 936 rup->ru_oublock = 0; 937 rup->ru_msgsnd = 0; 938 rup->ru_msgrcv = 0; 939 rup->ru_nsignals = 0; 940 rup->ru_nvcsw = 0; 941 rup->ru_nivcsw = 0; 942 943 rup.copyOut(tc->getMemPort()); 944 945 return 0; 946} 947 948 949 950 951#endif // __SIM_SYSCALL_EMUL_HH__ 952