syscall_emul.hh revision 11624
1/* 2 * Copyright (c) 2012-2013, 2015 ARM Limited 3 * Copyright (c) 2015 Advanced Micro Devices, Inc. 4 * All rights reserved 5 * 6 * The license below extends only to copyright in the software and shall 7 * not be construed as granting a license to any other intellectual 8 * property including but not limited to intellectual property relating 9 * to a hardware implementation of the functionality of the software 10 * licensed hereunder. You may use the software subject to the license 11 * terms below provided that you ensure that this notice is replicated 12 * unmodified and in its entirety in all distributions of the software, 13 * modified or unmodified, in source code or in binary form. 14 * 15 * Copyright (c) 2003-2005 The Regents of The University of Michigan 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Authors: Steve Reinhardt 42 * Kevin Lim 43 */ 44 45#ifndef __SIM_SYSCALL_EMUL_HH__ 46#define __SIM_SYSCALL_EMUL_HH__ 47 48#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 49 defined(__FreeBSD__) || defined(__CYGWIN__) || \ 50 defined(__NetBSD__)) 51 52/// 53/// @file syscall_emul.hh 54/// 55/// This file defines objects used to emulate syscalls from the target 56/// application on the host machine. 57 58#ifdef __CYGWIN32__ 59#include <sys/fcntl.h> // for O_BINARY 60 61#endif 62#include <fcntl.h> 63#include <sys/mman.h> 64#include <sys/stat.h> 65#include <sys/time.h> 66#include <sys/uio.h> 67#include <unistd.h> 68 69#include <cerrno> 70#include <string> 71 72#include "base/chunk_generator.hh" 73#include "base/intmath.hh" // for RoundUp 74#include "base/loader/object_file.hh" 75#include "base/misc.hh" 76#include "base/trace.hh" 77#include "base/types.hh" 78#include "config/the_isa.hh" 79#include "cpu/base.hh" 80#include "cpu/thread_context.hh" 81#include "debug/SyscallBase.hh" 82#include "debug/SyscallVerbose.hh" 83#include "mem/page_table.hh" 84#include "sim/byteswap.hh" 85#include "sim/emul_driver.hh" 86#include "sim/process.hh" 87#include "sim/syscall_emul_buf.hh" 88#include "sim/syscallreturn.hh" 89#include "sim/system.hh" 90 91// This wrapper macro helps out with readability a bit. FLAGEXT specifies 92// the verbosity and FMT is the message to be appended to the syscall 93// header information. The syscall header information contains the cpuid 94// and thread id. 95#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...) \ 96 DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT, \ 97 tc->threadId(), __VA_ARGS__) 98 99/// 100/// System call descriptor. 101/// 102class SyscallDesc { 103 104 public: 105 106 /// Typedef for target syscall handler functions. 107 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 108 LiveProcess *, ThreadContext *); 109 110 const char *name; //!< Syscall name (e.g., "open"). 111 FuncPtr funcPtr; //!< Pointer to emulation function. 112 int flags; //!< Flags (see Flags enum). 113 bool warned; //!< Have we warned about unimplemented syscall? 114 115 /// Flag values for controlling syscall behavior. 116 enum Flags { 117 /// Don't set return regs according to funcPtr return value. 118 /// Used for syscalls with non-standard return conventions 119 /// that explicitly set the ThreadContext regs (e.g., 120 /// sigreturn). 121 SuppressReturnValue = 1, 122 WarnOnce = 2 123 }; 124 125 /// Constructor. 126 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 127 : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false) 128 { 129 } 130 131 /// Emulate the syscall. Public interface for calling through funcPtr. 132 void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 133 134 /// Is the WarnOnce flag set? 135 bool warnOnce() const { return (flags & WarnOnce); } 136}; 137 138 139////////////////////////////////////////////////////////////////////// 140// 141// The following emulation functions are generic enough that they 142// don't need to be recompiled for different emulated OS's. They are 143// defined in sim/syscall_emul.cc. 144// 145////////////////////////////////////////////////////////////////////// 146 147 148/// Handler for unimplemented syscalls that we haven't thought about. 149SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 150 LiveProcess *p, ThreadContext *tc); 151 152/// Handler for unimplemented syscalls that we never intend to 153/// implement (signal handling, etc.) and should not affect the correct 154/// behavior of the program. Print a warning only if the appropriate 155/// trace flag is enabled. Return success to the target program. 156SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 157 LiveProcess *p, ThreadContext *tc); 158 159/// Target exit() handler: terminate current context. 160SyscallReturn exitFunc(SyscallDesc *desc, int num, 161 LiveProcess *p, ThreadContext *tc); 162 163/// Target exit_group() handler: terminate simulation. (exit all threads) 164SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 165 LiveProcess *p, ThreadContext *tc); 166 167/// Target getpagesize() handler. 168SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 169 LiveProcess *p, ThreadContext *tc); 170 171/// Target brk() handler: set brk address. 172SyscallReturn brkFunc(SyscallDesc *desc, int num, 173 LiveProcess *p, ThreadContext *tc); 174 175/// Target close() handler. 176SyscallReturn closeFunc(SyscallDesc *desc, int num, 177 LiveProcess *p, ThreadContext *tc); 178 179/// Target read() handler. 180SyscallReturn readFunc(SyscallDesc *desc, int num, 181 LiveProcess *p, ThreadContext *tc); 182 183/// Target write() handler. 184SyscallReturn writeFunc(SyscallDesc *desc, int num, 185 LiveProcess *p, ThreadContext *tc); 186 187/// Target lseek() handler. 188SyscallReturn lseekFunc(SyscallDesc *desc, int num, 189 LiveProcess *p, ThreadContext *tc); 190 191/// Target _llseek() handler. 192SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 193 LiveProcess *p, ThreadContext *tc); 194 195/// Target munmap() handler. 196SyscallReturn munmapFunc(SyscallDesc *desc, int num, 197 LiveProcess *p, ThreadContext *tc); 198 199/// Target gethostname() handler. 200SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 201 LiveProcess *p, ThreadContext *tc); 202 203/// Target getcwd() handler. 204SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 205 LiveProcess *p, ThreadContext *tc); 206 207/// Target readlink() handler. 208SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 209 LiveProcess *p, ThreadContext *tc, 210 int index = 0); 211SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 212 LiveProcess *p, ThreadContext *tc); 213 214/// Target unlink() handler. 215SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 216 LiveProcess *p, ThreadContext *tc, 217 int index); 218SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 219 LiveProcess *p, ThreadContext *tc); 220 221/// Target mkdir() handler. 222SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 223 LiveProcess *p, ThreadContext *tc); 224 225/// Target rename() handler. 226SyscallReturn renameFunc(SyscallDesc *desc, int num, 227 LiveProcess *p, ThreadContext *tc); 228 229 230/// Target truncate() handler. 231SyscallReturn truncateFunc(SyscallDesc *desc, int num, 232 LiveProcess *p, ThreadContext *tc); 233 234 235/// Target ftruncate() handler. 236SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 237 LiveProcess *p, ThreadContext *tc); 238 239 240/// Target truncate64() handler. 241SyscallReturn truncate64Func(SyscallDesc *desc, int num, 242 LiveProcess *p, ThreadContext *tc); 243 244/// Target ftruncate64() handler. 245SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 246 LiveProcess *p, ThreadContext *tc); 247 248 249/// Target umask() handler. 250SyscallReturn umaskFunc(SyscallDesc *desc, int num, 251 LiveProcess *p, ThreadContext *tc); 252 253 254/// Target chown() handler. 255SyscallReturn chownFunc(SyscallDesc *desc, int num, 256 LiveProcess *p, ThreadContext *tc); 257 258 259/// Target fchown() handler. 260SyscallReturn fchownFunc(SyscallDesc *desc, int num, 261 LiveProcess *p, ThreadContext *tc); 262 263/// Target dup() handler. 264SyscallReturn dupFunc(SyscallDesc *desc, int num, 265 LiveProcess *process, ThreadContext *tc); 266 267/// Target fnctl() handler. 268SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 269 LiveProcess *process, ThreadContext *tc); 270 271/// Target fcntl64() handler. 272SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 273 LiveProcess *process, ThreadContext *tc); 274 275/// Target setuid() handler. 276SyscallReturn setuidFunc(SyscallDesc *desc, int num, 277 LiveProcess *p, ThreadContext *tc); 278 279/// Target getpid() handler. 280SyscallReturn getpidFunc(SyscallDesc *desc, int num, 281 LiveProcess *p, ThreadContext *tc); 282 283/// Target getuid() handler. 284SyscallReturn getuidFunc(SyscallDesc *desc, int num, 285 LiveProcess *p, ThreadContext *tc); 286 287/// Target getgid() handler. 288SyscallReturn getgidFunc(SyscallDesc *desc, int num, 289 LiveProcess *p, ThreadContext *tc); 290 291/// Target getppid() handler. 292SyscallReturn getppidFunc(SyscallDesc *desc, int num, 293 LiveProcess *p, ThreadContext *tc); 294 295/// Target geteuid() handler. 296SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 297 LiveProcess *p, ThreadContext *tc); 298 299/// Target getegid() handler. 300SyscallReturn getegidFunc(SyscallDesc *desc, int num, 301 LiveProcess *p, ThreadContext *tc); 302 303/// Target clone() handler. 304SyscallReturn cloneFunc(SyscallDesc *desc, int num, 305 LiveProcess *p, ThreadContext *tc); 306 307/// Target access() handler 308SyscallReturn accessFunc(SyscallDesc *desc, int num, 309 LiveProcess *p, ThreadContext *tc); 310SyscallReturn accessFunc(SyscallDesc *desc, int num, 311 LiveProcess *p, ThreadContext *tc, 312 int index); 313 314/// Futex system call 315/// Implemented by Daniel Sanchez 316/// Used by printf's in multi-threaded apps 317template <class OS> 318SyscallReturn 319futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 320 ThreadContext *tc) 321{ 322 int index_uaddr = 0; 323 int index_op = 1; 324 int index_val = 2; 325 int index_timeout = 3; 326 327 uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 328 int op = process->getSyscallArg(tc, index_op); 329 int val = process->getSyscallArg(tc, index_val); 330 uint64_t timeout = process->getSyscallArg(tc, index_timeout); 331 332 std::map<uint64_t, std::list<ThreadContext *> * > 333 &futex_map = tc->getSystemPtr()->futexMap; 334 335 DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 336 uaddr, op, val); 337 338 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 339 340 if (op == OS::TGT_FUTEX_WAIT) { 341 if (timeout != 0) { 342 warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 343 "we'll wait indefinitely"); 344 } 345 346 uint8_t *buf = new uint8_t[sizeof(int)]; 347 tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 348 int mem_val = *((int *)buf); 349 delete[] buf; 350 351 if (val != mem_val) { 352 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 353 "expected: %d\n", mem_val, val); 354 return -OS::TGT_EWOULDBLOCK; 355 } 356 357 // Queue the thread context 358 std::list<ThreadContext *> * tcWaitList; 359 if (futex_map.count(uaddr)) { 360 tcWaitList = futex_map.find(uaddr)->second; 361 } else { 362 tcWaitList = new std::list<ThreadContext *>(); 363 futex_map.insert(std::pair< uint64_t, 364 std::list<ThreadContext *> * >(uaddr, tcWaitList)); 365 } 366 tcWaitList->push_back(tc); 367 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 368 "thread context\n"); 369 tc->suspend(); 370 return 0; 371 } else if (op == OS::TGT_FUTEX_WAKE){ 372 int wokenUp = 0; 373 std::list<ThreadContext *> * tcWaitList; 374 if (futex_map.count(uaddr)) { 375 tcWaitList = futex_map.find(uaddr)->second; 376 while (tcWaitList->size() > 0 && wokenUp < val) { 377 tcWaitList->front()->activate(); 378 tcWaitList->pop_front(); 379 wokenUp++; 380 } 381 if (tcWaitList->empty()) { 382 futex_map.erase(uaddr); 383 delete tcWaitList; 384 } 385 } 386 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 387 "thread contexts\n", wokenUp); 388 return wokenUp; 389 } else { 390 warn("sys_futex: op %d is not implemented, just returning...", op); 391 return 0; 392 } 393 394} 395 396 397/// Pseudo Funcs - These functions use a different return convension, 398/// returning a second value in a register other than the normal return register 399SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 400 LiveProcess *process, ThreadContext *tc); 401 402/// Target getpidPseudo() handler. 403SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 404 LiveProcess *p, ThreadContext *tc); 405 406/// Target getuidPseudo() handler. 407SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 408 LiveProcess *p, ThreadContext *tc); 409 410/// Target getgidPseudo() handler. 411SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 412 LiveProcess *p, ThreadContext *tc); 413 414 415/// A readable name for 1,000,000, for converting microseconds to seconds. 416const int one_million = 1000000; 417/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 418const int one_billion = 1000000000; 419 420/// Approximate seconds since the epoch (1/1/1970). About a billion, 421/// by my reckoning. We want to keep this a constant (not use the 422/// real-world time) to keep simulations repeatable. 423const unsigned seconds_since_epoch = 1000000000; 424 425/// Helper function to convert current elapsed time to seconds and 426/// microseconds. 427template <class T1, class T2> 428void 429getElapsedTimeMicro(T1 &sec, T2 &usec) 430{ 431 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 432 sec = elapsed_usecs / one_million; 433 usec = elapsed_usecs % one_million; 434} 435 436/// Helper function to convert current elapsed time to seconds and 437/// nanoseconds. 438template <class T1, class T2> 439void 440getElapsedTimeNano(T1 &sec, T2 &nsec) 441{ 442 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 443 sec = elapsed_nsecs / one_billion; 444 nsec = elapsed_nsecs % one_billion; 445} 446 447////////////////////////////////////////////////////////////////////// 448// 449// The following emulation functions are generic, but need to be 450// templated to account for differences in types, constants, etc. 451// 452////////////////////////////////////////////////////////////////////// 453 454#if NO_STAT64 455 typedef struct stat hst_stat; 456 typedef struct stat hst_stat64; 457#else 458 typedef struct stat hst_stat; 459 typedef struct stat64 hst_stat64; 460#endif 461 462//// Helper function to convert a host stat buffer to a target stat 463//// buffer. Also copies the target buffer out to the simulated 464//// memory space. Used by stat(), fstat(), and lstat(). 465 466template <typename target_stat, typename host_stat> 467static void 468convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 469{ 470 using namespace TheISA; 471 472 if (fakeTTY) 473 tgt->st_dev = 0xA; 474 else 475 tgt->st_dev = host->st_dev; 476 tgt->st_dev = TheISA::htog(tgt->st_dev); 477 tgt->st_ino = host->st_ino; 478 tgt->st_ino = TheISA::htog(tgt->st_ino); 479 tgt->st_mode = host->st_mode; 480 if (fakeTTY) { 481 // Claim to be a character device 482 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 483 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 484 } 485 tgt->st_mode = TheISA::htog(tgt->st_mode); 486 tgt->st_nlink = host->st_nlink; 487 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 488 tgt->st_uid = host->st_uid; 489 tgt->st_uid = TheISA::htog(tgt->st_uid); 490 tgt->st_gid = host->st_gid; 491 tgt->st_gid = TheISA::htog(tgt->st_gid); 492 if (fakeTTY) 493 tgt->st_rdev = 0x880d; 494 else 495 tgt->st_rdev = host->st_rdev; 496 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 497 tgt->st_size = host->st_size; 498 tgt->st_size = TheISA::htog(tgt->st_size); 499 tgt->st_atimeX = host->st_atime; 500 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 501 tgt->st_mtimeX = host->st_mtime; 502 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 503 tgt->st_ctimeX = host->st_ctime; 504 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 505 // Force the block size to be 8k. This helps to ensure buffered io works 506 // consistently across different hosts. 507 tgt->st_blksize = 0x2000; 508 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 509 tgt->st_blocks = host->st_blocks; 510 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 511} 512 513// Same for stat64 514 515template <typename target_stat, typename host_stat64> 516static void 517convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 518{ 519 using namespace TheISA; 520 521 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 522#if defined(STAT_HAVE_NSEC) 523 tgt->st_atime_nsec = host->st_atime_nsec; 524 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 525 tgt->st_mtime_nsec = host->st_mtime_nsec; 526 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 527 tgt->st_ctime_nsec = host->st_ctime_nsec; 528 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 529#else 530 tgt->st_atime_nsec = 0; 531 tgt->st_mtime_nsec = 0; 532 tgt->st_ctime_nsec = 0; 533#endif 534} 535 536//Here are a couple convenience functions 537template<class OS> 538static void 539copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 540 hst_stat *host, bool fakeTTY = false) 541{ 542 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 543 tgt_stat_buf tgt(addr); 544 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 545 tgt.copyOut(mem); 546} 547 548template<class OS> 549static void 550copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 551 hst_stat64 *host, bool fakeTTY = false) 552{ 553 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 554 tgt_stat_buf tgt(addr); 555 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 556 tgt.copyOut(mem); 557} 558 559/// Target ioctl() handler. For the most part, programs call ioctl() 560/// only to find out if their stdout is a tty, to determine whether to 561/// do line or block buffering. We always claim that output fds are 562/// not TTYs to provide repeatable results. 563template <class OS> 564SyscallReturn 565ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 566 ThreadContext *tc) 567{ 568 int index = 0; 569 int tgt_fd = process->getSyscallArg(tc, index); 570 unsigned req = process->getSyscallArg(tc, index); 571 572 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 573 574 FDEntry *fde = process->getFDEntry(tgt_fd); 575 576 if (fde == NULL) { 577 // doesn't map to any simulator fd: not a valid target fd 578 return -EBADF; 579 } 580 581 if (fde->driver != NULL) { 582 return fde->driver->ioctl(process, tc, req); 583 } 584 585 if (OS::isTtyReq(req)) { 586 return -ENOTTY; 587 } 588 589 warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 590 tgt_fd, req, tc->pcState()); 591 return -ENOTTY; 592} 593 594template <class OS> 595static SyscallReturn 596openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 597 ThreadContext *tc, int index) 598{ 599 std::string path; 600 601 if (!tc->getMemProxy().tryReadString(path, 602 process->getSyscallArg(tc, index))) 603 return -EFAULT; 604 605 int tgtFlags = process->getSyscallArg(tc, index); 606 int mode = process->getSyscallArg(tc, index); 607 int hostFlags = 0; 608 609 // translate open flags 610 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 611 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 612 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 613 hostFlags |= OS::openFlagTable[i].hostFlag; 614 } 615 } 616 617 // any target flags left? 618 if (tgtFlags != 0) 619 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 620 621#ifdef __CYGWIN32__ 622 hostFlags |= O_BINARY; 623#endif 624 625 // Adjust path for current working directory 626 path = process->fullPath(path); 627 628 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 629 630 if (startswith(path, "/dev/")) { 631 std::string filename = path.substr(strlen("/dev/")); 632 if (filename == "sysdev0") { 633 // This is a memory-mapped high-resolution timer device on Alpha. 634 // We don't support it, so just punt. 635 warn("Ignoring open(%s, ...)\n", path); 636 return -ENOENT; 637 } 638 639 EmulatedDriver *drv = process->findDriver(filename); 640 if (drv != NULL) { 641 // the driver's open method will allocate a fd from the 642 // process if necessary. 643 return drv->open(process, tc, mode, hostFlags); 644 } 645 646 // fall through here for pass through to host devices, such as 647 // /dev/zero 648 } 649 650 int fd; 651 int local_errno; 652 if (startswith(path, "/proc/") || startswith(path, "/system/") || 653 startswith(path, "/platform/") || startswith(path, "/sys/")) { 654 // It's a proc/sys entry and requires special handling 655 fd = OS::openSpecialFile(path, process, tc); 656 local_errno = ENOENT; 657 } else { 658 // open the file 659 fd = open(path.c_str(), hostFlags, mode); 660 local_errno = errno; 661 } 662 663 if (fd == -1) 664 return -local_errno; 665 666 return process->allocFD(fd, path.c_str(), hostFlags, mode, false); 667} 668 669/// Target open() handler. 670template <class OS> 671SyscallReturn 672openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 673 ThreadContext *tc) 674{ 675 return openFunc<OS>(desc, callnum, process, tc, 0); 676} 677 678/// Target openat() handler. 679template <class OS> 680SyscallReturn 681openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 682 ThreadContext *tc) 683{ 684 int index = 0; 685 int dirfd = process->getSyscallArg(tc, index); 686 if (dirfd != OS::TGT_AT_FDCWD) 687 warn("openat: first argument not AT_FDCWD; unlikely to work"); 688 return openFunc<OS>(desc, callnum, process, tc, 1); 689} 690 691/// Target unlinkat() handler. 692template <class OS> 693SyscallReturn 694unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 695 ThreadContext *tc) 696{ 697 int index = 0; 698 int dirfd = process->getSyscallArg(tc, index); 699 if (dirfd != OS::TGT_AT_FDCWD) 700 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 701 702 return unlinkHelper(desc, callnum, process, tc, 1); 703} 704 705/// Target facessat() handler 706template <class OS> 707SyscallReturn 708faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 709 ThreadContext *tc) 710{ 711 int index = 0; 712 int dirfd = process->getSyscallArg(tc, index); 713 if (dirfd != OS::TGT_AT_FDCWD) 714 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 715 return accessFunc(desc, callnum, process, tc, 1); 716} 717 718/// Target readlinkat() handler 719template <class OS> 720SyscallReturn 721readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 722 ThreadContext *tc) 723{ 724 int index = 0; 725 int dirfd = process->getSyscallArg(tc, index); 726 if (dirfd != OS::TGT_AT_FDCWD) 727 warn("openat: first argument not AT_FDCWD; unlikely to work"); 728 return readlinkFunc(desc, callnum, process, tc, 1); 729} 730 731/// Target renameat() handler. 732template <class OS> 733SyscallReturn 734renameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 735 ThreadContext *tc) 736{ 737 int index = 0; 738 739 int olddirfd = process->getSyscallArg(tc, index); 740 if (olddirfd != OS::TGT_AT_FDCWD) 741 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 742 743 std::string old_name; 744 745 if (!tc->getMemProxy().tryReadString(old_name, 746 process->getSyscallArg(tc, index))) 747 return -EFAULT; 748 749 int newdirfd = process->getSyscallArg(tc, index); 750 if (newdirfd != OS::TGT_AT_FDCWD) 751 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 752 753 std::string new_name; 754 755 if (!tc->getMemProxy().tryReadString(new_name, 756 process->getSyscallArg(tc, index))) 757 return -EFAULT; 758 759 // Adjust path for current working directory 760 old_name = process->fullPath(old_name); 761 new_name = process->fullPath(new_name); 762 763 int result = rename(old_name.c_str(), new_name.c_str()); 764 return (result == -1) ? -errno : result; 765} 766 767/// Target sysinfo() handler. 768template <class OS> 769SyscallReturn 770sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 771 ThreadContext *tc) 772{ 773 774 int index = 0; 775 TypedBufferArg<typename OS::tgt_sysinfo> 776 sysinfo(process->getSyscallArg(tc, index)); 777 778 sysinfo->uptime=seconds_since_epoch; 779 sysinfo->totalram=process->system->memSize(); 780 781 sysinfo.copyOut(tc->getMemProxy()); 782 783 return 0; 784} 785 786/// Target chmod() handler. 787template <class OS> 788SyscallReturn 789chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 790 ThreadContext *tc) 791{ 792 std::string path; 793 794 int index = 0; 795 if (!tc->getMemProxy().tryReadString(path, 796 process->getSyscallArg(tc, index))) { 797 return -EFAULT; 798 } 799 800 uint32_t mode = process->getSyscallArg(tc, index); 801 mode_t hostMode = 0; 802 803 // XXX translate mode flags via OS::something??? 804 hostMode = mode; 805 806 // Adjust path for current working directory 807 path = process->fullPath(path); 808 809 // do the chmod 810 int result = chmod(path.c_str(), hostMode); 811 if (result < 0) 812 return -errno; 813 814 return 0; 815} 816 817 818/// Target fchmod() handler. 819template <class OS> 820SyscallReturn 821fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 822 ThreadContext *tc) 823{ 824 int index = 0; 825 int tgt_fd = process->getSyscallArg(tc, index); 826 uint32_t mode = process->getSyscallArg(tc, index); 827 828 int sim_fd = process->getSimFD(tgt_fd); 829 if (sim_fd < 0) 830 return -EBADF; 831 832 mode_t hostMode = 0; 833 834 // XXX translate mode flags via OS::someting??? 835 hostMode = mode; 836 837 // do the fchmod 838 int result = fchmod(sim_fd, hostMode); 839 if (result < 0) 840 return -errno; 841 842 return 0; 843} 844 845/// Target mremap() handler. 846template <class OS> 847SyscallReturn 848mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 849{ 850 int index = 0; 851 Addr start = process->getSyscallArg(tc, index); 852 uint64_t old_length = process->getSyscallArg(tc, index); 853 uint64_t new_length = process->getSyscallArg(tc, index); 854 uint64_t flags = process->getSyscallArg(tc, index); 855 uint64_t provided_address = 0; 856 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 857 858 if (use_provided_address) 859 provided_address = process->getSyscallArg(tc, index); 860 861 if ((start % TheISA::PageBytes != 0) || 862 (provided_address % TheISA::PageBytes != 0)) { 863 warn("mremap failing: arguments not page aligned"); 864 return -EINVAL; 865 } 866 867 new_length = roundUp(new_length, TheISA::PageBytes); 868 869 if (new_length > old_length) { 870 if ((start + old_length) == process->mmap_end && 871 (!use_provided_address || provided_address == start)) { 872 uint64_t diff = new_length - old_length; 873 process->allocateMem(process->mmap_end, diff); 874 process->mmap_end += diff; 875 return start; 876 } else { 877 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 878 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 879 return -ENOMEM; 880 } else { 881 uint64_t new_start = use_provided_address ? 882 provided_address : process->mmap_end; 883 process->pTable->remap(start, old_length, new_start); 884 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 885 new_start, new_start + new_length, 886 new_length - old_length); 887 // add on the remaining unallocated pages 888 process->allocateMem(new_start + old_length, 889 new_length - old_length, 890 use_provided_address /* clobber */); 891 if (!use_provided_address) 892 process->mmap_end += new_length; 893 if (use_provided_address && 894 new_start + new_length > process->mmap_end) { 895 // something fishy going on here, at least notify the user 896 // @todo: increase mmap_end? 897 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 898 } 899 warn("returning %08p as start\n", new_start); 900 return new_start; 901 } 902 } 903 } else { 904 if (use_provided_address && provided_address != start) 905 process->pTable->remap(start, new_length, provided_address); 906 process->pTable->unmap(start + new_length, old_length - new_length); 907 return use_provided_address ? provided_address : start; 908 } 909} 910 911/// Target stat() handler. 912template <class OS> 913SyscallReturn 914statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 915 ThreadContext *tc) 916{ 917 std::string path; 918 919 int index = 0; 920 if (!tc->getMemProxy().tryReadString(path, 921 process->getSyscallArg(tc, index))) { 922 return -EFAULT; 923 } 924 Addr bufPtr = process->getSyscallArg(tc, index); 925 926 // Adjust path for current working directory 927 path = process->fullPath(path); 928 929 struct stat hostBuf; 930 int result = stat(path.c_str(), &hostBuf); 931 932 if (result < 0) 933 return -errno; 934 935 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 936 937 return 0; 938} 939 940 941/// Target stat64() handler. 942template <class OS> 943SyscallReturn 944stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 945 ThreadContext *tc) 946{ 947 std::string path; 948 949 int index = 0; 950 if (!tc->getMemProxy().tryReadString(path, 951 process->getSyscallArg(tc, index))) 952 return -EFAULT; 953 Addr bufPtr = process->getSyscallArg(tc, index); 954 955 // Adjust path for current working directory 956 path = process->fullPath(path); 957 958#if NO_STAT64 959 struct stat hostBuf; 960 int result = stat(path.c_str(), &hostBuf); 961#else 962 struct stat64 hostBuf; 963 int result = stat64(path.c_str(), &hostBuf); 964#endif 965 966 if (result < 0) 967 return -errno; 968 969 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 970 971 return 0; 972} 973 974 975/// Target fstatat64() handler. 976template <class OS> 977SyscallReturn 978fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 979 ThreadContext *tc) 980{ 981 int index = 0; 982 int dirfd = process->getSyscallArg(tc, index); 983 if (dirfd != OS::TGT_AT_FDCWD) 984 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 985 986 std::string path; 987 if (!tc->getMemProxy().tryReadString(path, 988 process->getSyscallArg(tc, index))) 989 return -EFAULT; 990 Addr bufPtr = process->getSyscallArg(tc, index); 991 992 // Adjust path for current working directory 993 path = process->fullPath(path); 994 995#if NO_STAT64 996 struct stat hostBuf; 997 int result = stat(path.c_str(), &hostBuf); 998#else 999 struct stat64 hostBuf; 1000 int result = stat64(path.c_str(), &hostBuf); 1001#endif 1002 1003 if (result < 0) 1004 return -errno; 1005 1006 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1007 1008 return 0; 1009} 1010 1011 1012/// Target fstat64() handler. 1013template <class OS> 1014SyscallReturn 1015fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1016 ThreadContext *tc) 1017{ 1018 int index = 0; 1019 int tgt_fd = process->getSyscallArg(tc, index); 1020 Addr bufPtr = process->getSyscallArg(tc, index); 1021 1022 int sim_fd = process->getSimFD(tgt_fd); 1023 if (sim_fd < 0) 1024 return -EBADF; 1025 1026#if NO_STAT64 1027 struct stat hostBuf; 1028 int result = fstat(sim_fd, &hostBuf); 1029#else 1030 struct stat64 hostBuf; 1031 int result = fstat64(sim_fd, &hostBuf); 1032#endif 1033 1034 if (result < 0) 1035 return -errno; 1036 1037 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1038 1039 return 0; 1040} 1041 1042 1043/// Target lstat() handler. 1044template <class OS> 1045SyscallReturn 1046lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1047 ThreadContext *tc) 1048{ 1049 std::string path; 1050 1051 int index = 0; 1052 if (!tc->getMemProxy().tryReadString(path, 1053 process->getSyscallArg(tc, index))) { 1054 return -EFAULT; 1055 } 1056 Addr bufPtr = process->getSyscallArg(tc, index); 1057 1058 // Adjust path for current working directory 1059 path = process->fullPath(path); 1060 1061 struct stat hostBuf; 1062 int result = lstat(path.c_str(), &hostBuf); 1063 1064 if (result < 0) 1065 return -errno; 1066 1067 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1068 1069 return 0; 1070} 1071 1072/// Target lstat64() handler. 1073template <class OS> 1074SyscallReturn 1075lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1076 ThreadContext *tc) 1077{ 1078 std::string path; 1079 1080 int index = 0; 1081 if (!tc->getMemProxy().tryReadString(path, 1082 process->getSyscallArg(tc, index))) { 1083 return -EFAULT; 1084 } 1085 Addr bufPtr = process->getSyscallArg(tc, index); 1086 1087 // Adjust path for current working directory 1088 path = process->fullPath(path); 1089 1090#if NO_STAT64 1091 struct stat hostBuf; 1092 int result = lstat(path.c_str(), &hostBuf); 1093#else 1094 struct stat64 hostBuf; 1095 int result = lstat64(path.c_str(), &hostBuf); 1096#endif 1097 1098 if (result < 0) 1099 return -errno; 1100 1101 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1102 1103 return 0; 1104} 1105 1106/// Target fstat() handler. 1107template <class OS> 1108SyscallReturn 1109fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1110 ThreadContext *tc) 1111{ 1112 int index = 0; 1113 int tgt_fd = process->getSyscallArg(tc, index); 1114 Addr bufPtr = process->getSyscallArg(tc, index); 1115 1116 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1117 1118 int sim_fd = process->getSimFD(tgt_fd); 1119 if (sim_fd < 0) 1120 return -EBADF; 1121 1122 struct stat hostBuf; 1123 int result = fstat(sim_fd, &hostBuf); 1124 1125 if (result < 0) 1126 return -errno; 1127 1128 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1129 1130 return 0; 1131} 1132 1133 1134/// Target statfs() handler. 1135template <class OS> 1136SyscallReturn 1137statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1138 ThreadContext *tc) 1139{ 1140 std::string path; 1141 1142 int index = 0; 1143 if (!tc->getMemProxy().tryReadString(path, 1144 process->getSyscallArg(tc, index))) { 1145 return -EFAULT; 1146 } 1147 Addr bufPtr = process->getSyscallArg(tc, index); 1148 1149 // Adjust path for current working directory 1150 path = process->fullPath(path); 1151 1152 struct statfs hostBuf; 1153 int result = statfs(path.c_str(), &hostBuf); 1154 1155 if (result < 0) 1156 return -errno; 1157 1158 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1159 1160 return 0; 1161} 1162 1163 1164/// Target fstatfs() handler. 1165template <class OS> 1166SyscallReturn 1167fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1168 ThreadContext *tc) 1169{ 1170 int index = 0; 1171 int tgt_fd = process->getSyscallArg(tc, index); 1172 Addr bufPtr = process->getSyscallArg(tc, index); 1173 1174 int sim_fd = process->getSimFD(tgt_fd); 1175 if (sim_fd < 0) 1176 return -EBADF; 1177 1178 struct statfs hostBuf; 1179 int result = fstatfs(sim_fd, &hostBuf); 1180 1181 if (result < 0) 1182 return -errno; 1183 1184 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1185 1186 return 0; 1187} 1188 1189 1190/// Target writev() handler. 1191template <class OS> 1192SyscallReturn 1193writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1194 ThreadContext *tc) 1195{ 1196 int index = 0; 1197 int tgt_fd = process->getSyscallArg(tc, index); 1198 1199 int sim_fd = process->getSimFD(tgt_fd); 1200 if (sim_fd < 0) 1201 return -EBADF; 1202 1203 SETranslatingPortProxy &p = tc->getMemProxy(); 1204 uint64_t tiov_base = process->getSyscallArg(tc, index); 1205 size_t count = process->getSyscallArg(tc, index); 1206 struct iovec hiov[count]; 1207 for (size_t i = 0; i < count; ++i) { 1208 typename OS::tgt_iovec tiov; 1209 1210 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1211 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1212 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1213 hiov[i].iov_base = new char [hiov[i].iov_len]; 1214 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1215 hiov[i].iov_len); 1216 } 1217 1218 int result = writev(sim_fd, hiov, count); 1219 1220 for (size_t i = 0; i < count; ++i) 1221 delete [] (char *)hiov[i].iov_base; 1222 1223 if (result < 0) 1224 return -errno; 1225 1226 return result; 1227} 1228 1229/// Real mmap handler. 1230template <class OS> 1231SyscallReturn 1232mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 1233 bool is_mmap2) 1234{ 1235 int index = 0; 1236 Addr start = p->getSyscallArg(tc, index); 1237 uint64_t length = p->getSyscallArg(tc, index); 1238 int prot = p->getSyscallArg(tc, index); 1239 int tgt_flags = p->getSyscallArg(tc, index); 1240 int tgt_fd = p->getSyscallArg(tc, index); 1241 int offset = p->getSyscallArg(tc, index); 1242 1243 if (is_mmap2) 1244 offset *= TheISA::PageBytes; 1245 1246 if (start & (TheISA::PageBytes - 1) || 1247 offset & (TheISA::PageBytes - 1) || 1248 (tgt_flags & OS::TGT_MAP_PRIVATE && 1249 tgt_flags & OS::TGT_MAP_SHARED) || 1250 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1251 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1252 !length) { 1253 return -EINVAL; 1254 } 1255 1256 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1257 // With shared mmaps, there are two cases to consider: 1258 // 1) anonymous: writes should modify the mapping and this should be 1259 // visible to observers who share the mapping. Currently, it's 1260 // difficult to update the shared mapping because there's no 1261 // structure which maintains information about the which virtual 1262 // memory areas are shared. If that structure existed, it would be 1263 // possible to make the translations point to the same frames. 1264 // 2) file-backed: writes should modify the mapping and the file 1265 // which is backed by the mapping. The shared mapping problem is the 1266 // same as what was mentioned about the anonymous mappings. For 1267 // file-backed mappings, the writes to the file are difficult 1268 // because it requires syncing what the mapping holds with the file 1269 // that resides on the host system. So, any write on a real system 1270 // would cause the change to be propagated to the file mapping at 1271 // some point in the future (the inode is tracked along with the 1272 // mapping). This isn't guaranteed to always happen, but it usually 1273 // works well enough. The guarantee is provided by the msync system 1274 // call. We could force the change through with shared mappings with 1275 // a call to msync, but that again would require more information 1276 // than we currently maintain. 1277 warn("mmap: writing to shared mmap region is currently " 1278 "unsupported. The write succeeds on the target, but it " 1279 "will not be propagated to the host or shared mappings"); 1280 } 1281 1282 length = roundUp(length, TheISA::PageBytes); 1283 1284 int sim_fd = -1; 1285 uint8_t *pmap = nullptr; 1286 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1287 // Check for EmulatedDriver mmap 1288 FDEntry *fde = p->getFDEntry(tgt_fd); 1289 if (fde == NULL) 1290 return -EBADF; 1291 1292 if (fde->driver != NULL) { 1293 return fde->driver->mmap(p, tc, start, length, prot, 1294 tgt_flags, tgt_fd, offset); 1295 } 1296 sim_fd = fde->fd; 1297 1298 if (sim_fd < 0) 1299 return -EBADF; 1300 1301 pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1302 sim_fd, offset); 1303 1304 if (pmap == (decltype(pmap))-1) { 1305 warn("mmap: failed to map file into host address space"); 1306 return -errno; 1307 } 1308 } 1309 1310 // Extend global mmap region if necessary. Note that we ignore the 1311 // start address unless MAP_FIXED is specified. 1312 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1313 start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end; 1314 p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length; 1315 } 1316 1317 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1318 start, start + length - 1); 1319 1320 // We only allow mappings to overwrite existing mappings if 1321 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1322 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1323 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1324 if (clobber) { 1325 for (auto tc : p->system->threadContexts) { 1326 // If we might be overwriting old mappings, we need to 1327 // invalidate potentially stale mappings out of the TLBs. 1328 tc->getDTBPtr()->flushAll(); 1329 tc->getITBPtr()->flushAll(); 1330 } 1331 } 1332 1333 // Allocate physical memory and map it in. If the page table is already 1334 // mapped and clobber is not set, the simulator will issue throw a 1335 // fatal and bail out of the simulation. 1336 p->allocateMem(start, length, clobber); 1337 1338 // Transfer content into target address space. 1339 SETranslatingPortProxy &tp = tc->getMemProxy(); 1340 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1341 // In general, we should zero the mapped area for anonymous mappings, 1342 // with something like: 1343 // tp.memsetBlob(start, 0, length); 1344 // However, given that we don't support sparse mappings, and 1345 // some applications can map a couple of gigabytes of space 1346 // (intending sparse usage), that can get painfully expensive. 1347 // Fortunately, since we don't properly implement munmap either, 1348 // there's no danger of remapping used memory, so for now all 1349 // newly mapped memory should already be zeroed so we can skip it. 1350 } else { 1351 // It is possible to mmap an area larger than a file, however 1352 // accessing unmapped portions the system triggers a "Bus error" 1353 // on the host. We must know when to stop copying the file from 1354 // the host into the target address space. 1355 struct stat file_stat; 1356 if (fstat(sim_fd, &file_stat) > 0) 1357 fatal("mmap: cannot stat file"); 1358 1359 // Copy the portion of the file that is resident. This requires 1360 // checking both the mmap size and the filesize that we are 1361 // trying to mmap into this space; the mmap size also depends 1362 // on the specified offset into the file. 1363 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1364 length); 1365 tp.writeBlob(start, pmap, size); 1366 1367 // Cleanup the mmap region before exiting this function. 1368 munmap(pmap, length); 1369 1370 // Maintain the symbol table for dynamic executables. 1371 // The loader will call mmap to map the images into its address 1372 // space and we intercept that here. We can verify that we are 1373 // executing inside the loader by checking the program counter value. 1374 // XXX: with multiprogrammed workloads or multi-node configurations, 1375 // this will not work since there is a single global symbol table. 1376 ObjectFile *interpreter = p->getInterpreter(); 1377 if (interpreter) { 1378 Addr text_start = interpreter->textBase(); 1379 Addr text_end = text_start + interpreter->textSize(); 1380 1381 Addr pc = tc->pcState().pc(); 1382 1383 if (pc >= text_start && pc < text_end) { 1384 FDEntry *fde = p->getFDEntry(tgt_fd); 1385 1386 ObjectFile *lib = createObjectFile(fde->filename); 1387 1388 if (lib) { 1389 lib->loadAllSymbols(debugSymbolTable, 1390 lib->textBase(), start); 1391 } 1392 } 1393 } 1394 1395 // Note that we do not zero out the remainder of the mapping. This 1396 // is done by a real system, but it probably will not affect 1397 // execution (hopefully). 1398 } 1399 1400 return start; 1401} 1402 1403template <class OS> 1404SyscallReturn 1405pwrite64Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1406{ 1407 int index = 0; 1408 int tgt_fd = p->getSyscallArg(tc, index); 1409 Addr bufPtr = p->getSyscallArg(tc, index); 1410 int nbytes = p->getSyscallArg(tc, index); 1411 int offset = p->getSyscallArg(tc, index); 1412 1413 int sim_fd = p->getSimFD(tgt_fd); 1414 if (sim_fd < 0) 1415 return -EBADF; 1416 1417 BufferArg bufArg(bufPtr, nbytes); 1418 bufArg.copyIn(tc->getMemProxy()); 1419 1420 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1421 1422 return (bytes_written == -1) ? -errno : bytes_written; 1423} 1424 1425/// Target mmap() handler. 1426template <class OS> 1427SyscallReturn 1428mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1429{ 1430 return mmapImpl<OS>(desc, num, p, tc, false); 1431} 1432 1433/// Target mmap2() handler. 1434template <class OS> 1435SyscallReturn 1436mmap2Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1437{ 1438 return mmapImpl<OS>(desc, num, p, tc, true); 1439} 1440 1441/// Target getrlimit() handler. 1442template <class OS> 1443SyscallReturn 1444getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1445 ThreadContext *tc) 1446{ 1447 int index = 0; 1448 unsigned resource = process->getSyscallArg(tc, index); 1449 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1450 1451 switch (resource) { 1452 case OS::TGT_RLIMIT_STACK: 1453 // max stack size in bytes: make up a number (8MB for now) 1454 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1455 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1456 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1457 break; 1458 1459 case OS::TGT_RLIMIT_DATA: 1460 // max data segment size in bytes: make up a number 1461 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1462 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1463 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1464 break; 1465 1466 default: 1467 warn("getrlimit: unimplemented resource %d", resource); 1468 return -EINVAL; 1469 break; 1470 } 1471 1472 rlp.copyOut(tc->getMemProxy()); 1473 return 0; 1474} 1475 1476/// Target clock_gettime() function. 1477template <class OS> 1478SyscallReturn 1479clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1480{ 1481 int index = 1; 1482 //int clk_id = p->getSyscallArg(tc, index); 1483 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1484 1485 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1486 tp->tv_sec += seconds_since_epoch; 1487 tp->tv_sec = TheISA::htog(tp->tv_sec); 1488 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1489 1490 tp.copyOut(tc->getMemProxy()); 1491 1492 return 0; 1493} 1494 1495/// Target clock_getres() function. 1496template <class OS> 1497SyscallReturn 1498clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1499{ 1500 int index = 1; 1501 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1502 1503 // Set resolution at ns, which is what clock_gettime() returns 1504 tp->tv_sec = 0; 1505 tp->tv_nsec = 1; 1506 1507 tp.copyOut(tc->getMemProxy()); 1508 1509 return 0; 1510} 1511 1512/// Target gettimeofday() handler. 1513template <class OS> 1514SyscallReturn 1515gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1516 ThreadContext *tc) 1517{ 1518 int index = 0; 1519 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1520 1521 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1522 tp->tv_sec += seconds_since_epoch; 1523 tp->tv_sec = TheISA::htog(tp->tv_sec); 1524 tp->tv_usec = TheISA::htog(tp->tv_usec); 1525 1526 tp.copyOut(tc->getMemProxy()); 1527 1528 return 0; 1529} 1530 1531 1532/// Target utimes() handler. 1533template <class OS> 1534SyscallReturn 1535utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1536 ThreadContext *tc) 1537{ 1538 std::string path; 1539 1540 int index = 0; 1541 if (!tc->getMemProxy().tryReadString(path, 1542 process->getSyscallArg(tc, index))) { 1543 return -EFAULT; 1544 } 1545 1546 TypedBufferArg<typename OS::timeval [2]> 1547 tp(process->getSyscallArg(tc, index)); 1548 tp.copyIn(tc->getMemProxy()); 1549 1550 struct timeval hostTimeval[2]; 1551 for (int i = 0; i < 2; ++i) 1552 { 1553 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1554 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1555 } 1556 1557 // Adjust path for current working directory 1558 path = process->fullPath(path); 1559 1560 int result = utimes(path.c_str(), hostTimeval); 1561 1562 if (result < 0) 1563 return -errno; 1564 1565 return 0; 1566} 1567/// Target getrusage() function. 1568template <class OS> 1569SyscallReturn 1570getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1571 ThreadContext *tc) 1572{ 1573 int index = 0; 1574 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1575 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1576 1577 rup->ru_utime.tv_sec = 0; 1578 rup->ru_utime.tv_usec = 0; 1579 rup->ru_stime.tv_sec = 0; 1580 rup->ru_stime.tv_usec = 0; 1581 rup->ru_maxrss = 0; 1582 rup->ru_ixrss = 0; 1583 rup->ru_idrss = 0; 1584 rup->ru_isrss = 0; 1585 rup->ru_minflt = 0; 1586 rup->ru_majflt = 0; 1587 rup->ru_nswap = 0; 1588 rup->ru_inblock = 0; 1589 rup->ru_oublock = 0; 1590 rup->ru_msgsnd = 0; 1591 rup->ru_msgrcv = 0; 1592 rup->ru_nsignals = 0; 1593 rup->ru_nvcsw = 0; 1594 rup->ru_nivcsw = 0; 1595 1596 switch (who) { 1597 case OS::TGT_RUSAGE_SELF: 1598 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1599 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1600 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1601 break; 1602 1603 case OS::TGT_RUSAGE_CHILDREN: 1604 // do nothing. We have no child processes, so they take no time. 1605 break; 1606 1607 default: 1608 // don't really handle THREAD or CHILDREN, but just warn and 1609 // plow ahead 1610 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1611 who); 1612 } 1613 1614 rup.copyOut(tc->getMemProxy()); 1615 1616 return 0; 1617} 1618 1619/// Target times() function. 1620template <class OS> 1621SyscallReturn 1622timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1623 ThreadContext *tc) 1624{ 1625 int index = 0; 1626 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1627 1628 // Fill in the time structure (in clocks) 1629 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1630 bufp->tms_utime = clocks; 1631 bufp->tms_stime = 0; 1632 bufp->tms_cutime = 0; 1633 bufp->tms_cstime = 0; 1634 1635 // Convert to host endianness 1636 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1637 1638 // Write back 1639 bufp.copyOut(tc->getMemProxy()); 1640 1641 // Return clock ticks since system boot 1642 return clocks; 1643} 1644 1645/// Target time() function. 1646template <class OS> 1647SyscallReturn 1648timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1649 ThreadContext *tc) 1650{ 1651 typename OS::time_t sec, usec; 1652 getElapsedTimeMicro(sec, usec); 1653 sec += seconds_since_epoch; 1654 1655 int index = 0; 1656 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1657 if (taddr != 0) { 1658 typename OS::time_t t = sec; 1659 t = TheISA::htog(t); 1660 SETranslatingPortProxy &p = tc->getMemProxy(); 1661 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1662 } 1663 return sec; 1664} 1665 1666 1667#endif // __SIM_SYSCALL_EMUL_HH__ 1668