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