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