syscall_emul.hh revision 4061
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 // Force the block size to be 8k. This helps to ensure buffered io works 381 // consistently across different hosts. 382 tgt->st_blksize = 0x2000; 383 tgt->st_blksize = htog(tgt->st_blksize); 384 tgt->st_blocks = host->st_blocks; 385 tgt->st_blocks = htog(tgt->st_blocks); 386} 387 388// Same for stat64 389 390template <typename target_stat, typename host_stat64> 391static void 392convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 393{ 394 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 395#if defined(STAT_HAVE_NSEC) 396 tgt->st_atime_nsec = host->st_atime_nsec; 397 tgt->st_atime_nsec = htog(tgt->st_atime_nsec); 398 tgt->st_mtime_nsec = host->st_mtime_nsec; 399 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec); 400 tgt->st_ctime_nsec = host->st_ctime_nsec; 401 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec); 402#else 403 tgt->st_atime_nsec = 0; 404 tgt->st_mtime_nsec = 0; 405 tgt->st_ctime_nsec = 0; 406#endif 407} 408 409//Here are a couple convenience functions 410template<class OS> 411static void 412copyOutStatBuf(TranslatingPort * mem, Addr addr, 413 hst_stat *host, bool fakeTTY = false) 414{ 415 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 416 tgt_stat_buf tgt(addr); 417 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 418 tgt.copyOut(mem); 419} 420 421template<class OS> 422static void 423copyOutStat64Buf(TranslatingPort * mem, Addr addr, 424 hst_stat64 *host, bool fakeTTY = false) 425{ 426 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 427 tgt_stat_buf tgt(addr); 428 convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 429 tgt.copyOut(mem); 430} 431 432/// Target ioctl() handler. For the most part, programs call ioctl() 433/// only to find out if their stdout is a tty, to determine whether to 434/// do line or block buffering. 435template <class OS> 436SyscallReturn 437ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 438 ThreadContext *tc) 439{ 440 int fd = tc->getSyscallArg(0); 441 unsigned req = tc->getSyscallArg(1); 442 443 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 444 445 if (fd < 0 || process->sim_fd(fd) < 0) { 446 // doesn't map to any simulator fd: not a valid target fd 447 return -EBADF; 448 } 449 450 switch (req) { 451 case OS::TIOCISATTY: 452 case OS::TIOCGETP: 453 case OS::TIOCSETP: 454 case OS::TIOCSETN: 455 case OS::TIOCSETC: 456 case OS::TIOCGETC: 457 case OS::TIOCGETS: 458 case OS::TIOCGETA: 459 return -ENOTTY; 460 461 default: 462 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 463 fd, req, tc->readPC()); 464 } 465} 466 467/// Target open() handler. 468template <class OS> 469SyscallReturn 470openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 471 ThreadContext *tc) 472{ 473 std::string path; 474 475 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 476 return -EFAULT; 477 478 if (path == "/dev/sysdev0") { 479 // This is a memory-mapped high-resolution timer device on Alpha. 480 // We don't support it, so just punt. 481 warn("Ignoring open(%s, ...)\n", path); 482 return -ENOENT; 483 } 484 485 int tgtFlags = tc->getSyscallArg(1); 486 int mode = tc->getSyscallArg(2); 487 int hostFlags = 0; 488 489 // translate open flags 490 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 491 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 492 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 493 hostFlags |= OS::openFlagTable[i].hostFlag; 494 } 495 } 496 497 // any target flags left? 498 if (tgtFlags != 0) 499 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 500 501#ifdef __CYGWIN32__ 502 hostFlags |= O_BINARY; 503#endif 504 505 // Adjust path for current working directory 506 path = process->fullPath(path); 507 508 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 509 510 // open the file 511 int fd = open(path.c_str(), hostFlags, mode); 512 513 return (fd == -1) ? -errno : process->alloc_fd(fd); 514} 515 516 517/// Target chmod() handler. 518template <class OS> 519SyscallReturn 520chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 521 ThreadContext *tc) 522{ 523 std::string path; 524 525 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 526 return -EFAULT; 527 528 uint32_t mode = tc->getSyscallArg(1); 529 mode_t hostMode = 0; 530 531 // XXX translate mode flags via OS::something??? 532 hostMode = mode; 533 534 // Adjust path for current working directory 535 path = process->fullPath(path); 536 537 // do the chmod 538 int result = chmod(path.c_str(), hostMode); 539 if (result < 0) 540 return -errno; 541 542 return 0; 543} 544 545 546/// Target fchmod() handler. 547template <class OS> 548SyscallReturn 549fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 550 ThreadContext *tc) 551{ 552 int fd = tc->getSyscallArg(0); 553 if (fd < 0 || process->sim_fd(fd) < 0) { 554 // doesn't map to any simulator fd: not a valid target fd 555 return -EBADF; 556 } 557 558 uint32_t mode = tc->getSyscallArg(1); 559 mode_t hostMode = 0; 560 561 // XXX translate mode flags via OS::someting??? 562 hostMode = mode; 563 564 // do the fchmod 565 int result = fchmod(process->sim_fd(fd), hostMode); 566 if (result < 0) 567 return -errno; 568 569 return 0; 570} 571 572 573/// Target stat() handler. 574template <class OS> 575SyscallReturn 576statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 577 ThreadContext *tc) 578{ 579 std::string path; 580 581 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 582 return -EFAULT; 583 584 // Adjust path for current working directory 585 path = process->fullPath(path); 586 587 struct stat hostBuf; 588 int result = stat(path.c_str(), &hostBuf); 589 590 if (result < 0) 591 return -errno; 592 593 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 594 595 return 0; 596} 597 598 599/// Target fstat64() handler. 600template <class OS> 601SyscallReturn 602fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 603 ThreadContext *tc) 604{ 605 int fd = tc->getSyscallArg(0); 606 if (fd < 0 || process->sim_fd(fd) < 0) { 607 // doesn't map to any simulator fd: not a valid target fd 608 return -EBADF; 609 } 610 611#if NO_STAT64 612 struct stat hostBuf; 613 int result = fstat(process->sim_fd(fd), &hostBuf); 614#else 615 struct stat64 hostBuf; 616 int result = fstat64(process->sim_fd(fd), &hostBuf); 617#endif 618 619 if (result < 0) 620 return -errno; 621 622 copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), 623 &hostBuf, (fd == 1)); 624 625 return 0; 626} 627 628 629/// Target lstat() handler. 630template <class OS> 631SyscallReturn 632lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 633 ThreadContext *tc) 634{ 635 std::string path; 636 637 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 638 return -EFAULT; 639 640 // Adjust path for current working directory 641 path = process->fullPath(path); 642 643 struct stat hostBuf; 644 int result = lstat(path.c_str(), &hostBuf); 645 646 if (result < 0) 647 return -errno; 648 649 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 650 651 return 0; 652} 653 654/// Target lstat64() handler. 655template <class OS> 656SyscallReturn 657lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 658 ThreadContext *tc) 659{ 660 std::string path; 661 662 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 663 return -EFAULT; 664 665 // Adjust path for current working directory 666 path = process->fullPath(path); 667 668#if NO_STAT64 669 struct stat hostBuf; 670 int result = lstat(path.c_str(), &hostBuf); 671#else 672 struct stat64 hostBuf; 673 int result = lstat64(path.c_str(), &hostBuf); 674#endif 675 676 if (result < 0) 677 return -errno; 678 679 copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 680 681 return 0; 682} 683 684/// Target fstat() handler. 685template <class OS> 686SyscallReturn 687fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 688 ThreadContext *tc) 689{ 690 int fd = process->sim_fd(tc->getSyscallArg(0)); 691 692 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 693 694 if (fd < 0) 695 return -EBADF; 696 697 struct stat hostBuf; 698 int result = fstat(fd, &hostBuf); 699 700 if (result < 0) 701 return -errno; 702 703 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), 704 &hostBuf, (fd == 1)); 705 706 return 0; 707} 708 709 710/// Target statfs() handler. 711template <class OS> 712SyscallReturn 713statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 714 ThreadContext *tc) 715{ 716 std::string path; 717 718 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 719 return -EFAULT; 720 721 // Adjust path for current working directory 722 path = process->fullPath(path); 723 724 struct statfs hostBuf; 725 int result = statfs(path.c_str(), &hostBuf); 726 727 if (result < 0) 728 return -errno; 729 730 OS::copyOutStatfsBuf(tc->getMemPort(), 731 (Addr)(tc->getSyscallArg(1)), &hostBuf); 732 733 return 0; 734} 735 736 737/// Target fstatfs() handler. 738template <class OS> 739SyscallReturn 740fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 741 ThreadContext *tc) 742{ 743 int fd = process->sim_fd(tc->getSyscallArg(0)); 744 745 if (fd < 0) 746 return -EBADF; 747 748 struct statfs hostBuf; 749 int result = fstatfs(fd, &hostBuf); 750 751 if (result < 0) 752 return -errno; 753 754 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), 755 &hostBuf); 756 757 return 0; 758} 759 760 761/// Target writev() handler. 762template <class OS> 763SyscallReturn 764writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 765 ThreadContext *tc) 766{ 767 int fd = tc->getSyscallArg(0); 768 if (fd < 0 || process->sim_fd(fd) < 0) { 769 // doesn't map to any simulator fd: not a valid target fd 770 return -EBADF; 771 } 772 773 TranslatingPort *p = tc->getMemPort(); 774 uint64_t tiov_base = tc->getSyscallArg(1); 775 size_t count = tc->getSyscallArg(2); 776 struct iovec hiov[count]; 777 for (int i = 0; i < count; ++i) 778 { 779 typename OS::tgt_iovec tiov; 780 781 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 782 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 783 hiov[i].iov_len = gtoh(tiov.iov_len); 784 hiov[i].iov_base = new char [hiov[i].iov_len]; 785 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 786 hiov[i].iov_len); 787 } 788 789 int result = writev(process->sim_fd(fd), hiov, count); 790 791 for (int i = 0; i < count; ++i) 792 { 793 delete [] (char *)hiov[i].iov_base; 794 } 795 796 if (result < 0) 797 return -errno; 798 799 return 0; 800} 801 802 803/// Target mmap() handler. 804/// 805/// We don't really handle mmap(). If the target is mmaping an 806/// anonymous region or /dev/zero, we can get away with doing basically 807/// nothing (since memory is initialized to zero and the simulator 808/// doesn't really check addresses anyway). Always print a warning, 809/// since this could be seriously broken if we're not mapping 810/// /dev/zero. 811// 812/// Someday we should explicitly check for /dev/zero in open, flag the 813/// file descriptor, and fail (or implement!) a non-anonymous mmap to 814/// anything else. 815template <class OS> 816SyscallReturn 817mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 818{ 819 Addr start = tc->getSyscallArg(0); 820 uint64_t length = tc->getSyscallArg(1); 821 // int prot = tc->getSyscallArg(2); 822 int flags = tc->getSyscallArg(3); 823 // int fd = p->sim_fd(tc->getSyscallArg(4)); 824 // int offset = tc->getSyscallArg(5); 825 826 if ((start % TheISA::VMPageSize) != 0 || 827 (length % TheISA::VMPageSize) != 0) { 828 warn("mmap failing: arguments not page-aligned: " 829 "start 0x%x length 0x%x", 830 start, length); 831 return -EINVAL; 832 } 833 834 if (start != 0) { 835 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 836 start, p->mmap_end); 837 } 838 839 // pick next address from our "mmap region" 840 start = p->mmap_end; 841 p->pTable->allocate(start, length); 842 p->mmap_end += length; 843 844 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 845 warn("allowing mmap of file @ fd %d. " 846 "This will break if not /dev/zero.", tc->getSyscallArg(4)); 847 } 848 849 return start; 850} 851 852/// Target getrlimit() handler. 853template <class OS> 854SyscallReturn 855getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 856 ThreadContext *tc) 857{ 858 unsigned resource = tc->getSyscallArg(0); 859 TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); 860 861 switch (resource) { 862 case OS::TGT_RLIMIT_STACK: 863 // max stack size in bytes: make up a number (2MB for now) 864 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 865 rlp->rlim_cur = htog(rlp->rlim_cur); 866 rlp->rlim_max = htog(rlp->rlim_max); 867 break; 868 869 default: 870 std::cerr << "getrlimitFunc: unimplemented resource " << resource 871 << std::endl; 872 abort(); 873 break; 874 } 875 876 rlp.copyOut(tc->getMemPort()); 877 return 0; 878} 879 880/// Target gettimeofday() handler. 881template <class OS> 882SyscallReturn 883gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 884 ThreadContext *tc) 885{ 886 TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); 887 888 getElapsedTime(tp->tv_sec, tp->tv_usec); 889 tp->tv_sec += seconds_since_epoch; 890 tp->tv_sec = htog(tp->tv_sec); 891 tp->tv_usec = htog(tp->tv_usec); 892 893 tp.copyOut(tc->getMemPort()); 894 895 return 0; 896} 897 898 899/// Target utimes() handler. 900template <class OS> 901SyscallReturn 902utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 903 ThreadContext *tc) 904{ 905 std::string path; 906 907 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 908 return -EFAULT; 909 910 TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); 911 tp.copyIn(tc->getMemPort()); 912 913 struct timeval hostTimeval[2]; 914 for (int i = 0; i < 2; ++i) 915 { 916 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 917 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 918 } 919 920 // Adjust path for current working directory 921 path = process->fullPath(path); 922 923 int result = utimes(path.c_str(), hostTimeval); 924 925 if (result < 0) 926 return -errno; 927 928 return 0; 929} 930/// Target getrusage() function. 931template <class OS> 932SyscallReturn 933getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 934 ThreadContext *tc) 935{ 936 int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 937 TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); 938 939 rup->ru_utime.tv_sec = 0; 940 rup->ru_utime.tv_usec = 0; 941 rup->ru_stime.tv_sec = 0; 942 rup->ru_stime.tv_usec = 0; 943 rup->ru_maxrss = 0; 944 rup->ru_ixrss = 0; 945 rup->ru_idrss = 0; 946 rup->ru_isrss = 0; 947 rup->ru_minflt = 0; 948 rup->ru_majflt = 0; 949 rup->ru_nswap = 0; 950 rup->ru_inblock = 0; 951 rup->ru_oublock = 0; 952 rup->ru_msgsnd = 0; 953 rup->ru_msgrcv = 0; 954 rup->ru_nsignals = 0; 955 rup->ru_nvcsw = 0; 956 rup->ru_nivcsw = 0; 957 958 switch (who) { 959 case OS::TGT_RUSAGE_SELF: 960 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 961 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 962 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 963 break; 964 965 case OS::TGT_RUSAGE_CHILDREN: 966 // do nothing. We have no child processes, so they take no time. 967 break; 968 969 default: 970 // don't really handle THREAD or CHILDREN, but just warn and 971 // plow ahead 972 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 973 who); 974 } 975 976 rup.copyOut(tc->getMemPort()); 977 978 return 0; 979} 980 981 982 983 984#endif // __SIM_SYSCALL_EMUL_HH__ 985