syscall_emul.hh revision 5208
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 _llseek() handler. 215SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 216 LiveProcess *p, ThreadContext *tc); 217 218/// Target munmap() handler. 219SyscallReturn munmapFunc(SyscallDesc *desc, int num, 220 LiveProcess *p, ThreadContext *tc); 221 222/// Target gethostname() handler. 223SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 224 LiveProcess *p, ThreadContext *tc); 225 226/// Target unlink() handler. 227SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 228 LiveProcess *p, ThreadContext *tc); 229 230/// Target rename() handler. 231SyscallReturn renameFunc(SyscallDesc *desc, int num, 232 LiveProcess *p, ThreadContext *tc); 233 234 235/// Target truncate() handler. 236SyscallReturn truncateFunc(SyscallDesc *desc, int num, 237 LiveProcess *p, ThreadContext *tc); 238 239 240/// Target ftruncate() handler. 241SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 242 LiveProcess *p, ThreadContext *tc); 243 244 245/// Target chown() handler. 246SyscallReturn chownFunc(SyscallDesc *desc, int num, 247 LiveProcess *p, ThreadContext *tc); 248 249 250/// Target fchown() handler. 251SyscallReturn fchownFunc(SyscallDesc *desc, int num, 252 LiveProcess *p, ThreadContext *tc); 253 254/// Target dup() handler. 255SyscallReturn dupFunc(SyscallDesc *desc, int num, 256 LiveProcess *process, ThreadContext *tc); 257 258/// Target fnctl() handler. 259SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 260 LiveProcess *process, ThreadContext *tc); 261 262/// Target fcntl64() handler. 263SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 264 LiveProcess *process, ThreadContext *tc); 265 266/// Target setuid() handler. 267SyscallReturn setuidFunc(SyscallDesc *desc, int num, 268 LiveProcess *p, ThreadContext *tc); 269 270/// Target getpid() handler. 271SyscallReturn getpidFunc(SyscallDesc *desc, int num, 272 LiveProcess *p, ThreadContext *tc); 273 274/// Target getuid() handler. 275SyscallReturn getuidFunc(SyscallDesc *desc, int num, 276 LiveProcess *p, ThreadContext *tc); 277 278/// Target getgid() handler. 279SyscallReturn getgidFunc(SyscallDesc *desc, int num, 280 LiveProcess *p, ThreadContext *tc); 281 282/// Target getppid() handler. 283SyscallReturn getppidFunc(SyscallDesc *desc, int num, 284 LiveProcess *p, ThreadContext *tc); 285 286/// Target geteuid() handler. 287SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 288 LiveProcess *p, ThreadContext *tc); 289 290/// Target getegid() handler. 291SyscallReturn getegidFunc(SyscallDesc *desc, int num, 292 LiveProcess *p, ThreadContext *tc); 293 294 295 296/// Pseudo Funcs - These functions use a different return convension, 297/// returning a second value in a register other than the normal return register 298SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 299 LiveProcess *process, ThreadContext *tc); 300 301/// Target getpidPseudo() handler. 302SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 303 LiveProcess *p, ThreadContext *tc); 304 305/// Target getuidPseudo() handler. 306SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 307 LiveProcess *p, ThreadContext *tc); 308 309/// Target getgidPseudo() handler. 310SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 311 LiveProcess *p, ThreadContext *tc); 312 313 314/// A readable name for 1,000,000, for converting microseconds to seconds. 315const int one_million = 1000000; 316 317/// Approximate seconds since the epoch (1/1/1970). About a billion, 318/// by my reckoning. We want to keep this a constant (not use the 319/// real-world time) to keep simulations repeatable. 320const unsigned seconds_since_epoch = 1000000000; 321 322/// Helper function to convert current elapsed time to seconds and 323/// microseconds. 324template <class T1, class T2> 325void 326getElapsedTime(T1 &sec, T2 &usec) 327{ 328 int elapsed_usecs = curTick / Clock::Int::us; 329 sec = elapsed_usecs / one_million; 330 usec = elapsed_usecs % one_million; 331} 332 333////////////////////////////////////////////////////////////////////// 334// 335// The following emulation functions are generic, but need to be 336// templated to account for differences in types, constants, etc. 337// 338////////////////////////////////////////////////////////////////////// 339 340#if NO_STAT64 341 typedef struct stat hst_stat; 342 typedef struct stat hst_stat64; 343#else 344 typedef struct stat hst_stat; 345 typedef struct stat64 hst_stat64; 346#endif 347 348//// Helper function to convert a host stat buffer to a target stat 349//// buffer. Also copies the target buffer out to the simulated 350//// memory space. Used by stat(), fstat(), and lstat(). 351 352template <typename target_stat, typename host_stat> 353static void 354convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 355{ 356 using namespace TheISA; 357 358 if (fakeTTY) 359 tgt->st_dev = 0xA; 360 else 361 tgt->st_dev = host->st_dev; 362 tgt->st_dev = htog(tgt->st_dev); 363 tgt->st_ino = host->st_ino; 364 tgt->st_ino = htog(tgt->st_ino); 365 tgt->st_mode = host->st_mode; 366 tgt->st_mode = htog(tgt->st_mode); 367 tgt->st_nlink = host->st_nlink; 368 tgt->st_nlink = htog(tgt->st_nlink); 369 tgt->st_uid = host->st_uid; 370 tgt->st_uid = htog(tgt->st_uid); 371 tgt->st_gid = host->st_gid; 372 tgt->st_gid = htog(tgt->st_gid); 373 if (fakeTTY) 374 tgt->st_rdev = 0x880d; 375 else 376 tgt->st_rdev = host->st_rdev; 377 tgt->st_rdev = htog(tgt->st_rdev); 378 tgt->st_size = host->st_size; 379 tgt->st_size = htog(tgt->st_size); 380 tgt->st_atimeX = host->st_atime; 381 tgt->st_atimeX = htog(tgt->st_atimeX); 382 tgt->st_mtimeX = host->st_mtime; 383 tgt->st_mtimeX = htog(tgt->st_mtimeX); 384 tgt->st_ctimeX = host->st_ctime; 385 tgt->st_ctimeX = htog(tgt->st_ctimeX); 386 // Force the block size to be 8k. This helps to ensure buffered io works 387 // consistently across different hosts. 388 tgt->st_blksize = 0x2000; 389 tgt->st_blksize = htog(tgt->st_blksize); 390 tgt->st_blocks = host->st_blocks; 391 tgt->st_blocks = htog(tgt->st_blocks); 392} 393 394// Same for stat64 395 396template <typename target_stat, typename host_stat64> 397static void 398convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 399{ 400 using namespace TheISA; 401 402 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 403#if defined(STAT_HAVE_NSEC) 404 tgt->st_atime_nsec = host->st_atime_nsec; 405 tgt->st_atime_nsec = htog(tgt->st_atime_nsec); 406 tgt->st_mtime_nsec = host->st_mtime_nsec; 407 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec); 408 tgt->st_ctime_nsec = host->st_ctime_nsec; 409 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec); 410#else 411 tgt->st_atime_nsec = 0; 412 tgt->st_mtime_nsec = 0; 413 tgt->st_ctime_nsec = 0; 414#endif 415} 416 417//Here are a couple convenience functions 418template<class OS> 419static void 420copyOutStatBuf(TranslatingPort * mem, Addr addr, 421 hst_stat *host, bool fakeTTY = false) 422{ 423 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 424 tgt_stat_buf tgt(addr); 425 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 426 tgt.copyOut(mem); 427} 428 429template<class OS> 430static void 431copyOutStat64Buf(TranslatingPort * mem, Addr addr, 432 hst_stat64 *host, bool fakeTTY = false) 433{ 434 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 435 tgt_stat_buf tgt(addr); 436 convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 437 tgt.copyOut(mem); 438} 439 440/// Target ioctl() handler. For the most part, programs call ioctl() 441/// only to find out if their stdout is a tty, to determine whether to 442/// do line or block buffering. 443template <class OS> 444SyscallReturn 445ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 446 ThreadContext *tc) 447{ 448 int fd = tc->getSyscallArg(0); 449 unsigned req = tc->getSyscallArg(1); 450 451 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 452 453 if (fd < 0 || process->sim_fd(fd) < 0) { 454 // doesn't map to any simulator fd: not a valid target fd 455 return -EBADF; 456 } 457 458 switch (req) { 459 case OS::TIOCISATTY_: 460 case OS::TIOCGETP_: 461 case OS::TIOCSETP_: 462 case OS::TIOCSETN_: 463 case OS::TIOCSETC_: 464 case OS::TIOCGETC_: 465 case OS::TIOCGETS_: 466 case OS::TIOCGETA_: 467 return -ENOTTY; 468 469 default: 470 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 471 fd, req, tc->readPC()); 472 } 473} 474 475/// Target open() handler. 476template <class OS> 477SyscallReturn 478openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 479 ThreadContext *tc) 480{ 481 std::string path; 482 483 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 484 return -EFAULT; 485 486 if (path == "/dev/sysdev0") { 487 // This is a memory-mapped high-resolution timer device on Alpha. 488 // We don't support it, so just punt. 489 warn("Ignoring open(%s, ...)\n", path); 490 return -ENOENT; 491 } 492 493 int tgtFlags = tc->getSyscallArg(1); 494 int mode = tc->getSyscallArg(2); 495 int hostFlags = 0; 496 497 // translate open flags 498 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 499 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 500 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 501 hostFlags |= OS::openFlagTable[i].hostFlag; 502 } 503 } 504 505 // any target flags left? 506 if (tgtFlags != 0) 507 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 508 509#ifdef __CYGWIN32__ 510 hostFlags |= O_BINARY; 511#endif 512 513 // Adjust path for current working directory 514 path = process->fullPath(path); 515 516 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 517 518 // open the file 519 int fd = open(path.c_str(), hostFlags, mode); 520 521 return (fd == -1) ? -errno : process->alloc_fd(fd); 522} 523 524 525/// Target chmod() handler. 526template <class OS> 527SyscallReturn 528chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 529 ThreadContext *tc) 530{ 531 std::string path; 532 533 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 534 return -EFAULT; 535 536 uint32_t mode = tc->getSyscallArg(1); 537 mode_t hostMode = 0; 538 539 // XXX translate mode flags via OS::something??? 540 hostMode = mode; 541 542 // Adjust path for current working directory 543 path = process->fullPath(path); 544 545 // do the chmod 546 int result = chmod(path.c_str(), hostMode); 547 if (result < 0) 548 return -errno; 549 550 return 0; 551} 552 553 554/// Target fchmod() handler. 555template <class OS> 556SyscallReturn 557fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 558 ThreadContext *tc) 559{ 560 int fd = tc->getSyscallArg(0); 561 if (fd < 0 || process->sim_fd(fd) < 0) { 562 // doesn't map to any simulator fd: not a valid target fd 563 return -EBADF; 564 } 565 566 uint32_t mode = tc->getSyscallArg(1); 567 mode_t hostMode = 0; 568 569 // XXX translate mode flags via OS::someting??? 570 hostMode = mode; 571 572 // do the fchmod 573 int result = fchmod(process->sim_fd(fd), hostMode); 574 if (result < 0) 575 return -errno; 576 577 return 0; 578} 579 580 581/// Target stat() handler. 582template <class OS> 583SyscallReturn 584statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 585 ThreadContext *tc) 586{ 587 std::string path; 588 589 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 590 return -EFAULT; 591 592 // Adjust path for current working directory 593 path = process->fullPath(path); 594 595 struct stat hostBuf; 596 int result = stat(path.c_str(), &hostBuf); 597 598 if (result < 0) 599 return -errno; 600 601 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 602 603 return 0; 604} 605 606 607/// Target stat64() handler. 608template <class OS> 609SyscallReturn 610stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 611 ThreadContext *tc) 612{ 613 std::string path; 614 615 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 616 return -EFAULT; 617 618 // Adjust path for current working directory 619 path = process->fullPath(path); 620 621#if NO_STAT64 622 struct stat hostBuf; 623 int result = stat(path.c_str(), &hostBuf); 624#else 625 struct stat64 hostBuf; 626 int result = stat64(path.c_str(), &hostBuf); 627#endif 628 629 if (result < 0) 630 return -errno; 631 632 copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 633 634 return 0; 635} 636 637 638/// Target fstat64() handler. 639template <class OS> 640SyscallReturn 641fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 642 ThreadContext *tc) 643{ 644 int fd = tc->getSyscallArg(0); 645 if (fd < 0 || process->sim_fd(fd) < 0) { 646 // doesn't map to any simulator fd: not a valid target fd 647 return -EBADF; 648 } 649 650#if NO_STAT64 651 struct stat hostBuf; 652 int result = fstat(process->sim_fd(fd), &hostBuf); 653#else 654 struct stat64 hostBuf; 655 int result = fstat64(process->sim_fd(fd), &hostBuf); 656#endif 657 658 if (result < 0) 659 return -errno; 660 661 copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), 662 &hostBuf, (fd == 1)); 663 664 return 0; 665} 666 667 668/// Target lstat() handler. 669template <class OS> 670SyscallReturn 671lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 672 ThreadContext *tc) 673{ 674 std::string path; 675 676 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 677 return -EFAULT; 678 679 // Adjust path for current working directory 680 path = process->fullPath(path); 681 682 struct stat hostBuf; 683 int result = lstat(path.c_str(), &hostBuf); 684 685 if (result < 0) 686 return -errno; 687 688 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 689 690 return 0; 691} 692 693/// Target lstat64() handler. 694template <class OS> 695SyscallReturn 696lstat64Func(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 // Adjust path for current working directory 705 path = process->fullPath(path); 706 707#if NO_STAT64 708 struct stat hostBuf; 709 int result = lstat(path.c_str(), &hostBuf); 710#else 711 struct stat64 hostBuf; 712 int result = lstat64(path.c_str(), &hostBuf); 713#endif 714 715 if (result < 0) 716 return -errno; 717 718 copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 719 720 return 0; 721} 722 723/// Target fstat() handler. 724template <class OS> 725SyscallReturn 726fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 727 ThreadContext *tc) 728{ 729 int fd = process->sim_fd(tc->getSyscallArg(0)); 730 731 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 732 733 if (fd < 0) 734 return -EBADF; 735 736 struct stat hostBuf; 737 int result = fstat(fd, &hostBuf); 738 739 if (result < 0) 740 return -errno; 741 742 copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), 743 &hostBuf, (fd == 1)); 744 745 return 0; 746} 747 748 749/// Target statfs() handler. 750template <class OS> 751SyscallReturn 752statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 753 ThreadContext *tc) 754{ 755 std::string path; 756 757 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 758 return -EFAULT; 759 760 // Adjust path for current working directory 761 path = process->fullPath(path); 762 763 struct statfs hostBuf; 764 int result = statfs(path.c_str(), &hostBuf); 765 766 if (result < 0) 767 return -errno; 768 769 OS::copyOutStatfsBuf(tc->getMemPort(), 770 (Addr)(tc->getSyscallArg(1)), &hostBuf); 771 772 return 0; 773} 774 775 776/// Target fstatfs() handler. 777template <class OS> 778SyscallReturn 779fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 780 ThreadContext *tc) 781{ 782 int fd = process->sim_fd(tc->getSyscallArg(0)); 783 784 if (fd < 0) 785 return -EBADF; 786 787 struct statfs hostBuf; 788 int result = fstatfs(fd, &hostBuf); 789 790 if (result < 0) 791 return -errno; 792 793 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), 794 &hostBuf); 795 796 return 0; 797} 798 799 800/// Target writev() handler. 801template <class OS> 802SyscallReturn 803writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 804 ThreadContext *tc) 805{ 806 int fd = tc->getSyscallArg(0); 807 if (fd < 0 || process->sim_fd(fd) < 0) { 808 // doesn't map to any simulator fd: not a valid target fd 809 return -EBADF; 810 } 811 812 TranslatingPort *p = tc->getMemPort(); 813 uint64_t tiov_base = tc->getSyscallArg(1); 814 size_t count = tc->getSyscallArg(2); 815 struct iovec hiov[count]; 816 for (int i = 0; i < count; ++i) 817 { 818 typename OS::tgt_iovec tiov; 819 820 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 821 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 822 hiov[i].iov_len = gtoh(tiov.iov_len); 823 hiov[i].iov_base = new char [hiov[i].iov_len]; 824 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 825 hiov[i].iov_len); 826 } 827 828 int result = writev(process->sim_fd(fd), hiov, count); 829 830 for (int i = 0; i < count; ++i) 831 { 832 delete [] (char *)hiov[i].iov_base; 833 } 834 835 if (result < 0) 836 return -errno; 837 838 return 0; 839} 840 841 842/// Target mmap() handler. 843/// 844/// We don't really handle mmap(). If the target is mmaping an 845/// anonymous region or /dev/zero, we can get away with doing basically 846/// nothing (since memory is initialized to zero and the simulator 847/// doesn't really check addresses anyway). Always print a warning, 848/// since this could be seriously broken if we're not mapping 849/// /dev/zero. 850// 851/// Someday we should explicitly check for /dev/zero in open, flag the 852/// file descriptor, and fail (or implement!) a non-anonymous mmap to 853/// anything else. 854template <class OS> 855SyscallReturn 856mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 857{ 858 Addr start = tc->getSyscallArg(0); 859 uint64_t length = tc->getSyscallArg(1); 860 // int prot = tc->getSyscallArg(2); 861 int flags = tc->getSyscallArg(3); 862 // int fd = p->sim_fd(tc->getSyscallArg(4)); 863 // int offset = tc->getSyscallArg(5); 864 865 if ((start % TheISA::VMPageSize) != 0 || 866 (length % TheISA::VMPageSize) != 0) { 867 warn("mmap failing: arguments not page-aligned: " 868 "start 0x%x length 0x%x", 869 start, length); 870 return -EINVAL; 871 } 872 873 if (start != 0) { 874 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 875 start, p->mmap_end); 876 } 877 878 // pick next address from our "mmap region" 879 start = p->mmap_end; 880 p->pTable->allocate(start, length); 881 p->mmap_end += length; 882 883 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 884 warn("allowing mmap of file @ fd %d. " 885 "This will break if not /dev/zero.", tc->getSyscallArg(4)); 886 } 887 888 return start; 889} 890 891/// Target getrlimit() handler. 892template <class OS> 893SyscallReturn 894getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 895 ThreadContext *tc) 896{ 897 unsigned resource = tc->getSyscallArg(0); 898 TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); 899 900 switch (resource) { 901 case OS::TGT_RLIMIT_STACK: 902 // max stack size in bytes: make up a number (2MB for now) 903 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 904 rlp->rlim_cur = htog(rlp->rlim_cur); 905 rlp->rlim_max = htog(rlp->rlim_max); 906 break; 907 908 default: 909 std::cerr << "getrlimitFunc: unimplemented resource " << resource 910 << std::endl; 911 abort(); 912 break; 913 } 914 915 rlp.copyOut(tc->getMemPort()); 916 return 0; 917} 918 919/// Target gettimeofday() handler. 920template <class OS> 921SyscallReturn 922gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 923 ThreadContext *tc) 924{ 925 TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); 926 927 getElapsedTime(tp->tv_sec, tp->tv_usec); 928 tp->tv_sec += seconds_since_epoch; 929 tp->tv_sec = htog(tp->tv_sec); 930 tp->tv_usec = htog(tp->tv_usec); 931 932 tp.copyOut(tc->getMemPort()); 933 934 return 0; 935} 936 937 938/// Target utimes() handler. 939template <class OS> 940SyscallReturn 941utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 942 ThreadContext *tc) 943{ 944 std::string path; 945 946 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 947 return -EFAULT; 948 949 TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); 950 tp.copyIn(tc->getMemPort()); 951 952 struct timeval hostTimeval[2]; 953 for (int i = 0; i < 2; ++i) 954 { 955 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 956 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 957 } 958 959 // Adjust path for current working directory 960 path = process->fullPath(path); 961 962 int result = utimes(path.c_str(), hostTimeval); 963 964 if (result < 0) 965 return -errno; 966 967 return 0; 968} 969/// Target getrusage() function. 970template <class OS> 971SyscallReturn 972getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 973 ThreadContext *tc) 974{ 975 int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 976 TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); 977 978 rup->ru_utime.tv_sec = 0; 979 rup->ru_utime.tv_usec = 0; 980 rup->ru_stime.tv_sec = 0; 981 rup->ru_stime.tv_usec = 0; 982 rup->ru_maxrss = 0; 983 rup->ru_ixrss = 0; 984 rup->ru_idrss = 0; 985 rup->ru_isrss = 0; 986 rup->ru_minflt = 0; 987 rup->ru_majflt = 0; 988 rup->ru_nswap = 0; 989 rup->ru_inblock = 0; 990 rup->ru_oublock = 0; 991 rup->ru_msgsnd = 0; 992 rup->ru_msgrcv = 0; 993 rup->ru_nsignals = 0; 994 rup->ru_nvcsw = 0; 995 rup->ru_nivcsw = 0; 996 997 switch (who) { 998 case OS::TGT_RUSAGE_SELF: 999 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1000 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 1001 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 1002 break; 1003 1004 case OS::TGT_RUSAGE_CHILDREN: 1005 // do nothing. We have no child processes, so they take no time. 1006 break; 1007 1008 default: 1009 // don't really handle THREAD or CHILDREN, but just warn and 1010 // plow ahead 1011 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1012 who); 1013 } 1014 1015 rup.copyOut(tc->getMemPort()); 1016 1017 return 0; 1018} 1019 1020 1021 1022 1023#endif // __SIM_SYSCALL_EMUL_HH__ 1024