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