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