syscall_emul.hh revision 2400
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 29#ifndef __SIM_SYSCALL_EMUL_HH__ 30#define __SIM_SYSCALL_EMUL_HH__ 31 32/// 33/// @file syscall_emul.hh 34/// 35/// This file defines objects used to emulate syscalls from the target 36/// application on the host machine. 37 38#include <errno.h> 39#include <string> 40#ifdef __CYGWIN32__ 41#include <sys/fcntl.h> // for O_BINARY 42#endif 43#include <sys/uio.h> 44 45#include "base/intmath.hh" // for RoundUp 46#include "mem/translating_port.hh" 47#include "targetarch/isa_traits.hh" // for Addr 48 49#include "base/trace.hh" 50#include "cpu/exec_context.hh" 51#include "cpu/base.hh" 52#include "sim/process.hh" 53 54/// 55/// System call descriptor. 56/// 57class SyscallDesc { 58 59 public: 60 61 /// Typedef for target syscall handler functions. 62 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 63 Process *, ExecContext *); 64 65 const char *name; //!< Syscall name (e.g., "open"). 66 FuncPtr funcPtr; //!< Pointer to emulation function. 67 int flags; //!< Flags (see Flags enum). 68 69 /// Flag values for controlling syscall behavior. 70 enum Flags { 71 /// Don't set return regs according to funcPtr return value. 72 /// Used for syscalls with non-standard return conventions 73 /// that explicitly set the ExecContext regs (e.g., 74 /// sigreturn). 75 SuppressReturnValue = 1 76 }; 77 78 /// Constructor. 79 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 80 : name(_name), funcPtr(_funcPtr), flags(_flags) 81 { 82 } 83 84 /// Emulate the syscall. Public interface for calling through funcPtr. 85 void doSyscall(int callnum, Process *proc, ExecContext *xc); 86}; 87 88 89class BaseBufferArg { 90 91 public: 92 93 BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 94 { 95 bufPtr = new uint8_t[size]; 96 // clear out buffer: in case we only partially populate this, 97 // and then do a copyOut(), we want to make sure we don't 98 // introduce any random junk into the simulated address space 99 memset(bufPtr, 0, size); 100 } 101 102 virtual ~BaseBufferArg() { delete [] bufPtr; } 103 104 // 105 // copy data into simulator space (read from target memory) 106 // 107 virtual bool copyIn(TranslatingPort *memport) 108 { 109 memport->readBlobFunctional(addr, bufPtr, size); 110 return true; // no EFAULT detection for now 111 } 112 113 // 114 // copy data out of simulator space (write to target memory) 115 // 116 virtual bool copyOut(TranslatingPort *memport) 117 { 118 memport->writeBlobFunctional(addr, bufPtr, size); 119 return true; // no EFAULT detection for now 120 } 121 122 protected: 123 Addr addr; 124 int size; 125 uint8_t *bufPtr; 126}; 127 128 129class BufferArg : public BaseBufferArg 130{ 131 public: 132 BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 133 void *bufferPtr() { return bufPtr; } 134}; 135 136template <class T> 137class TypedBufferArg : public BaseBufferArg 138{ 139 public: 140 // user can optionally specify a specific number of bytes to 141 // allocate to deal with those structs that have variable-size 142 // arrays at the end 143 TypedBufferArg(Addr _addr, int _size = sizeof(T)) 144 : BaseBufferArg(_addr, _size) 145 { } 146 147 // type case 148 operator T*() { return (T *)bufPtr; } 149 150 // dereference operators 151 T &operator*() { return *((T *)bufPtr); } 152 T* operator->() { return (T *)bufPtr; } 153 T &operator[](int i) { return ((T *)bufPtr)[i]; } 154}; 155 156////////////////////////////////////////////////////////////////////// 157// 158// The following emulation functions are generic enough that they 159// don't need to be recompiled for different emulated OS's. They are 160// defined in sim/syscall_emul.cc. 161// 162////////////////////////////////////////////////////////////////////// 163 164 165/// Handler for unimplemented syscalls that we haven't thought about. 166SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 167 Process *p, ExecContext *xc); 168 169/// Handler for unimplemented syscalls that we never intend to 170/// implement (signal handling, etc.) and should not affect the correct 171/// behavior of the program. Print a warning only if the appropriate 172/// trace flag is enabled. Return success to the target program. 173SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 174 Process *p, ExecContext *xc); 175 176/// Target exit() handler: terminate simulation. 177SyscallReturn exitFunc(SyscallDesc *desc, int num, 178 Process *p, ExecContext *xc); 179 180/// Target getpagesize() handler. 181SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 182 Process *p, ExecContext *xc); 183 184/// Target obreak() handler: set brk address. 185SyscallReturn obreakFunc(SyscallDesc *desc, int num, 186 Process *p, ExecContext *xc); 187 188/// Target close() handler. 189SyscallReturn closeFunc(SyscallDesc *desc, int num, 190 Process *p, ExecContext *xc); 191 192/// Target read() handler. 193SyscallReturn readFunc(SyscallDesc *desc, int num, 194 Process *p, ExecContext *xc); 195 196/// Target write() handler. 197SyscallReturn writeFunc(SyscallDesc *desc, int num, 198 Process *p, ExecContext *xc); 199 200/// Target lseek() handler. 201SyscallReturn lseekFunc(SyscallDesc *desc, int num, 202 Process *p, ExecContext *xc); 203 204/// Target munmap() handler. 205SyscallReturn munmapFunc(SyscallDesc *desc, int num, 206 Process *p, ExecContext *xc); 207 208/// Target gethostname() handler. 209SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 210 Process *p, ExecContext *xc); 211 212/// Target unlink() handler. 213SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 214 Process *p, ExecContext *xc); 215 216/// Target rename() handler. 217SyscallReturn renameFunc(SyscallDesc *desc, int num, 218 Process *p, ExecContext *xc); 219 220 221/// Target truncate() handler. 222SyscallReturn truncateFunc(SyscallDesc *desc, int num, 223 Process *p, ExecContext *xc); 224 225 226/// Target ftruncate() handler. 227SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 228 Process *p, ExecContext *xc); 229 230 231/// Target chown() handler. 232SyscallReturn chownFunc(SyscallDesc *desc, int num, 233 Process *p, ExecContext *xc); 234 235 236/// Target fchown() handler. 237SyscallReturn fchownFunc(SyscallDesc *desc, int num, 238 Process *p, ExecContext *xc); 239 240/// This struct is used to build an target-OS-dependent table that 241/// maps the target's open() flags to the host open() flags. 242struct OpenFlagTransTable { 243 int tgtFlag; //!< Target system flag value. 244 int hostFlag; //!< Corresponding host system flag value. 245}; 246 247 248 249/// A readable name for 1,000,000, for converting microseconds to seconds. 250const int one_million = 1000000; 251 252/// Approximate seconds since the epoch (1/1/1970). About a billion, 253/// by my reckoning. We want to keep this a constant (not use the 254/// real-world time) to keep simulations repeatable. 255const unsigned seconds_since_epoch = 1000000000; 256 257/// Helper function to convert current elapsed time to seconds and 258/// microseconds. 259template <class T1, class T2> 260void 261getElapsedTime(T1 &sec, T2 &usec) 262{ 263 int elapsed_usecs = curTick / Clock::Int::us; 264 sec = elapsed_usecs / one_million; 265 usec = elapsed_usecs % one_million; 266} 267 268////////////////////////////////////////////////////////////////////// 269// 270// The following emulation functions are generic, but need to be 271// templated to account for differences in types, constants, etc. 272// 273////////////////////////////////////////////////////////////////////// 274 275/// Target ioctl() handler. For the most part, programs call ioctl() 276/// only to find out if their stdout is a tty, to determine whether to 277/// do line or block buffering. 278template <class OS> 279SyscallReturn 280ioctlFunc(SyscallDesc *desc, int callnum, Process *process, 281 ExecContext *xc) 282{ 283 int fd = xc->getSyscallArg(0); 284 unsigned req = xc->getSyscallArg(1); 285 286 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 287 288 if (fd < 0 || process->sim_fd(fd) < 0) { 289 // doesn't map to any simulator fd: not a valid target fd 290 return -EBADF; 291 } 292 293 switch (req) { 294 case OS::TIOCISATTY: 295 case OS::TIOCGETP: 296 case OS::TIOCSETP: 297 case OS::TIOCSETN: 298 case OS::TIOCSETC: 299 case OS::TIOCGETC: 300 case OS::TIOCGETS: 301 case OS::TIOCGETA: 302 return -ENOTTY; 303 304 default: 305 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 306 fd, req, xc->readPC()); 307 } 308} 309 310/// Target open() handler. 311template <class OS> 312SyscallReturn 313openFunc(SyscallDesc *desc, int callnum, Process *process, 314 ExecContext *xc) 315{ 316 std::string path; 317 318 if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault) 319 return -EFAULT; 320 321 if (path == "/dev/sysdev0") { 322 // This is a memory-mapped high-resolution timer device on Alpha. 323 // We don't support it, so just punt. 324 warn("Ignoring open(%s, ...)\n", path); 325 return -ENOENT; 326 } 327 328 int tgtFlags = xc->getSyscallArg(1); 329 int mode = xc->getSyscallArg(2); 330 int hostFlags = 0; 331 332 // translate open flags 333 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 334 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 335 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 336 hostFlags |= OS::openFlagTable[i].hostFlag; 337 } 338 } 339 340 // any target flags left? 341 if (tgtFlags != 0) 342 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 343 344#ifdef __CYGWIN32__ 345 hostFlags |= O_BINARY; 346#endif 347 348 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 349 350 // open the file 351 int fd = open(path.c_str(), hostFlags, mode); 352 353 return (fd == -1) ? -errno : process->alloc_fd(fd); 354} 355 356 357/// Target chmod() handler. 358template <class OS> 359SyscallReturn 360chmodFunc(SyscallDesc *desc, int callnum, Process *process, 361 ExecContext *xc) 362{ 363 std::string path; 364 365 if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault) 366 return -EFAULT; 367 368 uint32_t mode = xc->getSyscallArg(1); 369 mode_t hostMode = 0; 370 371 // XXX translate mode flags via OS::something??? 372 hostMode = mode; 373 374 // do the chmod 375 int result = chmod(path.c_str(), hostMode); 376 if (result < 0) 377 return errno; 378 379 return 0; 380} 381 382 383/// Target fchmod() handler. 384template <class OS> 385SyscallReturn 386fchmodFunc(SyscallDesc *desc, int callnum, Process *process, 387 ExecContext *xc) 388{ 389 int fd = xc->getSyscallArg(0); 390 if (fd < 0 || process->sim_fd(fd) < 0) { 391 // doesn't map to any simulator fd: not a valid target fd 392 return -EBADF; 393 } 394 395 uint32_t mode = xc->getSyscallArg(1); 396 mode_t hostMode = 0; 397 398 // XXX translate mode flags via OS::someting??? 399 hostMode = mode; 400 401 // do the fchmod 402 int result = fchmod(process->sim_fd(fd), hostMode); 403 if (result < 0) 404 return errno; 405 406 return 0; 407} 408 409 410/// Target stat() handler. 411template <class OS> 412SyscallReturn 413statFunc(SyscallDesc *desc, int callnum, Process *process, 414 ExecContext *xc) 415{ 416 std::string path; 417 418 if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault) 419 return -EFAULT; 420 421 struct stat hostBuf; 422 int result = stat(path.c_str(), &hostBuf); 423 424 if (result < 0) 425 return errno; 426 427 OS::copyOutStatBuf(xc->port, xc->getSyscallArg(1), &hostBuf); 428 429 return 0; 430} 431 432 433/// Target fstat64() handler. 434template <class OS> 435SyscallReturn 436fstat64Func(SyscallDesc *desc, int callnum, Process *process, 437 ExecContext *xc) 438{ 439 int fd = xc->getSyscallArg(0); 440 if (fd < 0 || process->sim_fd(fd) < 0) { 441 // doesn't map to any simulator fd: not a valid target fd 442 return -EBADF; 443 } 444 445 struct stat64 hostBuf; 446 int result = fstat64(process->sim_fd(fd), &hostBuf); 447 448 if (result < 0) 449 return errno; 450 451 OS::copyOutStat64Buf(xc->port, xc->getSyscallArg(1), &hostBuf); 452 453 return 0; 454} 455 456 457/// Target lstat() handler. 458template <class OS> 459SyscallReturn 460lstatFunc(SyscallDesc *desc, int callnum, Process *process, 461 ExecContext *xc) 462{ 463 std::string path; 464 465 if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault) 466 return -EFAULT; 467 468 struct stat hostBuf; 469 int result = lstat(path.c_str(), &hostBuf); 470 471 if (result < 0) 472 return -errno; 473 474 OS::copyOutStatBuf(xc->port, xc->getSyscallArg(1), &hostBuf); 475 476 return 0; 477} 478 479/// Target lstat64() handler. 480template <class OS> 481SyscallReturn 482lstat64Func(SyscallDesc *desc, int callnum, Process *process, 483 ExecContext *xc) 484{ 485 std::string path; 486 487 if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault) 488 return -EFAULT; 489 490 struct stat64 hostBuf; 491 int result = lstat64(path.c_str(), &hostBuf); 492 493 if (result < 0) 494 return -errno; 495 496 OS::copyOutStat64Buf(xc->port, xc->getSyscallArg(1), &hostBuf); 497 498 return 0; 499} 500 501/// Target fstat() handler. 502template <class OS> 503SyscallReturn 504fstatFunc(SyscallDesc *desc, int callnum, Process *process, 505 ExecContext *xc) 506{ 507 int fd = process->sim_fd(xc->getSyscallArg(0)); 508 509 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 510 511 if (fd < 0) 512 return -EBADF; 513 514 struct stat hostBuf; 515 int result = fstat(fd, &hostBuf); 516 517 if (result < 0) 518 return -errno; 519 520 OS::copyOutStatBuf(xc->port, xc->getSyscallArg(1), &hostBuf); 521 522 return 0; 523} 524 525 526/// Target statfs() handler. 527template <class OS> 528SyscallReturn 529statfsFunc(SyscallDesc *desc, int callnum, Process *process, 530 ExecContext *xc) 531{ 532 std::string path; 533 534 if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault) 535 return -EFAULT; 536 537 struct statfs hostBuf; 538 int result = statfs(path.c_str(), &hostBuf); 539 540 if (result < 0) 541 return errno; 542 543 OS::copyOutStatfsBuf(xc->port, xc->getSyscallArg(1), &hostBuf); 544 545 return 0; 546} 547 548 549/// Target fstatfs() handler. 550template <class OS> 551SyscallReturn 552fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, 553 ExecContext *xc) 554{ 555 int fd = process->sim_fd(xc->getSyscallArg(0)); 556 557 if (fd < 0) 558 return -EBADF; 559 560 struct statfs hostBuf; 561 int result = fstatfs(fd, &hostBuf); 562 563 if (result < 0) 564 return errno; 565 566 OS::copyOutStatfsBuf(xc->port, xc->getSyscallArg(1), &hostBuf); 567 568 return 0; 569} 570 571 572/// Target writev() handler. 573template <class OS> 574SyscallReturn 575writevFunc(SyscallDesc *desc, int callnum, Process *process, 576 ExecContext *xc) 577{ 578 int fd = xc->getSyscallArg(0); 579 if (fd < 0 || process->sim_fd(fd) < 0) { 580 // doesn't map to any simulator fd: not a valid target fd 581 return -EBADF; 582 } 583 584 uint64_t tiov_base = xc->getSyscallArg(1); 585 size_t count = xc->getSyscallArg(2); 586 struct iovec hiov[count]; 587 for (int i = 0; i < count; ++i) 588 { 589 typename OS::tgt_iovec tiov; 590 xc->port->readBlobFunctional(tiov_base + i*sizeof(typename OS::tgt_iovec),(uint8_t*) 591 &tiov, sizeof(typename OS::tgt_iovec)); 592 hiov[i].iov_len = tiov.iov_len; 593 hiov[i].iov_base = new char [hiov[i].iov_len]; 594 xc->port->readBlobFunctional(tiov.iov_base, 595 (uint8_t *)hiov[i].iov_base, hiov[i].iov_len); 596 } 597 598 int result = writev(process->sim_fd(fd), hiov, count); 599 600 for (int i = 0; i < count; ++i) 601 { 602 delete [] (char *)hiov[i].iov_base; 603 } 604 605 if (result < 0) 606 return errno; 607 608 return 0; 609} 610 611 612/// Target mmap() handler. 613/// 614/// We don't really handle mmap(). If the target is mmaping an 615/// anonymous region or /dev/zero, we can get away with doing basically 616/// nothing (since memory is initialized to zero and the simulator 617/// doesn't really check addresses anyway). Always print a warning, 618/// since this could be seriously broken if we're not mapping 619/// /dev/zero. 620// 621/// Someday we should explicitly check for /dev/zero in open, flag the 622/// file descriptor, and fail (or implement!) a non-anonymous mmap to 623/// anything else. 624template <class OS> 625SyscallReturn 626mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 627{ 628 Addr start = xc->getSyscallArg(0); 629 uint64_t length = xc->getSyscallArg(1); 630 // int prot = xc->getSyscallArg(2); 631 int flags = xc->getSyscallArg(3); 632 // int fd = p->sim_fd(xc->getSyscallArg(4)); 633 // int offset = xc->getSyscallArg(5); 634 635 if (start == 0) { 636 // user didn't give an address... pick one from our "mmap region" 637 start = p->mmap_end; 638 p->mmap_end += roundUp(length, VMPageSize); 639 if (p->nxm_start != 0) { 640 //If we have an nxm space, make sure we haven't colided 641 assert(p->mmap_end < p->nxm_start); 642 } 643 } 644 645 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 646 warn("allowing mmap of file @ fd %d. " 647 "This will break if not /dev/zero.", xc->getSyscallArg(4)); 648 } 649 650 return start; 651} 652 653/// Target getrlimit() handler. 654template <class OS> 655SyscallReturn 656getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 657 ExecContext *xc) 658{ 659 unsigned resource = xc->getSyscallArg(0); 660 TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); 661 662 switch (resource) { 663 case OS::RLIMIT_STACK: 664 // max stack size in bytes: make up a number (2MB for now) 665 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 666 break; 667 668 default: 669 std::cerr << "getrlimitFunc: unimplemented resource " << resource 670 << std::endl; 671 abort(); 672 break; 673 } 674 675 rlp.copyOut(xc->port); 676 return 0; 677} 678 679/// Target gettimeofday() handler. 680template <class OS> 681SyscallReturn 682gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 683 ExecContext *xc) 684{ 685 TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); 686 687 getElapsedTime(tp->tv_sec, tp->tv_usec); 688 tp->tv_sec += seconds_since_epoch; 689 690 tp.copyOut(xc->port); 691 692 return 0; 693} 694 695 696/// Target utimes() handler. 697template <class OS> 698SyscallReturn 699utimesFunc(SyscallDesc *desc, int callnum, Process *process, 700 ExecContext *xc) 701{ 702 std::string path; 703 704 if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault) 705 return -EFAULT; 706 707 TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); 708 tp.copyIn(xc->port); 709 710 struct timeval hostTimeval[2]; 711 for (int i = 0; i < 2; ++i) 712 { 713 hostTimeval[i].tv_sec = (*tp)[i].tv_sec; 714 hostTimeval[i].tv_usec = (*tp)[i].tv_usec; 715 } 716 int result = utimes(path.c_str(), hostTimeval); 717 718 if (result < 0) 719 return -errno; 720 721 return 0; 722} 723 724/// Target getrusage() function. 725template <class OS> 726SyscallReturn 727getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 728 ExecContext *xc) 729{ 730 int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 731 TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); 732 733 if (who != OS::RUSAGE_SELF) { 734 // don't really handle THREAD or CHILDREN, but just warn and 735 // plow ahead 736 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 737 who); 738 } 739 740 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 741 rup->ru_stime.tv_sec = 0; 742 rup->ru_stime.tv_usec = 0; 743 rup->ru_maxrss = 0; 744 rup->ru_ixrss = 0; 745 rup->ru_idrss = 0; 746 rup->ru_isrss = 0; 747 rup->ru_minflt = 0; 748 rup->ru_majflt = 0; 749 rup->ru_nswap = 0; 750 rup->ru_inblock = 0; 751 rup->ru_oublock = 0; 752 rup->ru_msgsnd = 0; 753 rup->ru_msgrcv = 0; 754 rup->ru_nsignals = 0; 755 rup->ru_nvcsw = 0; 756 rup->ru_nivcsw = 0; 757 758 rup.copyOut(xc->port); 759 760 return 0; 761} 762 763#endif // __SIM_SYSCALL_EMUL_HH__ 764